Пример #1
0
 protected GeneratePackageAppxManifest GetNewTask(string manifest,
                                                  string?generatedFilename = null,
                                                  string?guid            = null,
                                                  string?displayVersion  = null,
                                                  string?version         = null,
                                                  string?displayName     = null,
                                                  ITaskItem?appIcon      = null,
                                                  ITaskItem?splashScreen = null) =>
Пример #2
0
        /// <summary>
        /// Main entry point.
        /// </summary>
        public override bool Execute()
        {
            if (String.IsNullOrEmpty(this.Language))
            {
                this.Log.LogErrorWithCodeFromResources("General.InvalidValue", nameof(this.Language), "WriteThisAssemblyCodeFile");
                return(false);
            }

            if (this.OutputFile == null && this.OutputDirectory == null)
            {
                this.Log.LogErrorWithCodeFromResources("WriteCodeFragment.MustSpecifyLocation");
                return(false);
            }

            var code = this.GenerateCode(out var extension);

            if (this.Log.HasLoggedErrors)
            {
                return(false);
            }

            if (code.Length == 0)
            {
                this.Log.LogMessageFromResources(MessageImportance.Low, "WriteCodeFragment.NoWorkToDo");
                this.OutputFile = null;
                return(true);
            }

            try
            {
                if (this.OutputFile != null && this.OutputDirectory != null && !Path.IsPathRooted(this.OutputFile.ItemSpec))
                {
                    this.OutputFile = new TaskItem(Path.Combine(this.OutputDirectory.ItemSpec, this.OutputFile.ItemSpec));
                }

                this.OutputFile ??= new TaskItem(FileUtilities.GetTemporaryFile(this.OutputDirectory !.ItemSpec, extension));

                File.WriteAllText(this.OutputFile.ItemSpec, code); // Overwrites file if it already exists (and can be overwritten)
            }
            catch (Exception ex) when(ExceptionHandling.IsIoRelatedException(ex))
            {
                this.Log.LogErrorWithCodeFromResources("WriteCodeFragment.CouldNotWriteOutput", (this.OutputFile == null) ? String.Empty : this.OutputFile.ItemSpec, ex.Message);
                return(false);
            }

            this.Log.LogMessageFromResources(MessageImportance.Low, "WriteCodeFragment.GeneratedFile", this.OutputFile.ItemSpec);

            return(!this.Log.HasLoggedErrors);
        }
Пример #3
0
        private Version GetVersion(ITaskItem?hostItem)
        {
            var versionAsString = hostItem?.GetMetadata(VersionMetadataName);

            if (!NullableString.IsNullOrEmpty(versionAsString))
            {
                if (Version.TryParse(versionAsString, out var version))
                {
                    return(version);
                }

                Log.LogError(CommonResources.ItemOfItemGroupMustSpecifyMetadata, hostItem !.ItemSpec, HostsItemGroupName, VersionMetadataName);
            }

            return(s_versionWithNewUrlFormat);
        }
Пример #4
0
        protected override string?BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem)
        {
            var virtualDirectory = hostItem?.GetMetadata(VirtualDirectoryMetadataName) ?? "";

            if (!AzureDevOpsUrlParser.TryParseOnPremHttp(relativeUrl, virtualDirectory, out var projectPath, out var repositoryName))
            {
                Log.LogError(CommonResources.ValueOfWithIdentityIsInvalid, Names.SourceRoot.RepositoryUrlFullName, SourceRoot.ItemSpec, gitUri);
                return(null);
            }

            return
                (UriUtilities.Combine(
                     UriUtilities.Combine(contentUri.ToString(), projectPath), $"_apis/git/repositories/{repositoryName}/items") +
                 $"?api-version=1.0&versionType=commit&version={revisionId}&path=/*");
        }
Пример #5
0
        private bool ExecuteActual()
        {
            if (SourceFiles.Length == 0)
            {
                Log.LogError($"No SourceFiles to compile");
                return(false);
            }

            ITaskItem?badItem = SourceFiles.FirstOrDefault(sf => string.IsNullOrEmpty(sf.GetMetadata("ObjectFile")));

            if (badItem != null)
            {
                Log.LogError($"Source file {badItem.ItemSpec} is missing ObjectFile metadata.");
                return(false);
            }

            if (!Enum.TryParse(OutputMessageImportance, ignoreCase: true, out MessageImportance messageImportance))
            {
                Log.LogError($"Invalid value for OutputMessageImportance={OutputMessageImportance}. Valid values: {string.Join(", ", Enum.GetNames(typeof(MessageImportance)))}");
                return(false);
            }

            _totalFiles = SourceFiles.Length;
            IDictionary <string, string> envVarsDict = GetEnvironmentVariablesDict();
            ConcurrentBag <ITaskItem>    outputItems = new();

            try
            {
                List <(string, string)> filesToCompile = new();
                foreach (ITaskItem srcItem in SourceFiles)
                {
                    string   srcFile     = srcItem.ItemSpec;
                    string   objFile     = srcItem.GetMetadata("ObjectFile");
                    string   depMetadata = srcItem.GetMetadata("Dependencies");
                    string[] depFiles    = string.IsNullOrEmpty(depMetadata)
                                            ? Array.Empty <string>()
                                            : depMetadata.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    if (!ShouldCompile(srcFile, objFile, depFiles, out string reason))
                    {
                        Log.LogMessage(MessageImportance.Low, $"Skipping {srcFile} because {reason}.");
                        outputItems.Add(CreateOutputItemFor(srcFile, objFile));
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Low, $"Compiling {srcFile} because {reason}.");
                        filesToCompile.Add((srcFile, objFile));
                    }
                }

                _numCompiled = SourceFiles.Length - filesToCompile.Count;
                if (_numCompiled == _totalFiles)
                {
                    // nothing to do!
                    OutputFiles = outputItems.ToArray();
                    return(!Log.HasLoggedErrors);
                }

                if (_numCompiled > 0)
                {
                    Log.LogMessage(MessageImportance.High, $"[{_numCompiled}/{SourceFiles.Length}] skipped unchanged files");
                }

                Log.LogMessage(MessageImportance.Low, "Using environment variables:");
                foreach (var kvp in envVarsDict)
                {
                    Log.LogMessage(MessageImportance.Low, $"\t{kvp.Key} = {kvp.Value}");
                }

                string workingDir = Environment.CurrentDirectory;
                Log.LogMessage(MessageImportance.Low, $"Using working directory: {workingDir}");

                _tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(_tempPath);

                int allowedParallelism = DisableParallelCompile ? 1 : Math.Min(SourceFiles.Length, Environment.ProcessorCount);
                if (BuildEngine is IBuildEngine9 be9)
                {
                    allowedParallelism = be9.RequestCores(allowedParallelism);
                }

                /*
                 *  From: https://github.com/dotnet/runtime/issues/46146#issuecomment-754021690
                 *
                 *  Stephen Toub:
                 *  "As such, by default ForEach works on a scheme whereby each
                 *  thread takes one item each time it goes back to the enumerator,
                 *  and then after a few times of this upgrades to taking two items
                 *  each time it goes back to the enumerator, and then four, and
                 *  then eight, and so on. This amortizes the cost of taking and
                 *  releasing the lock across multiple items, while still enabling
                 *  parallelization for enumerables containing just a few items. It
                 *  does, however, mean that if you've got a case where the body
                 *  takes a really long time and the work for every item is
                 *  heterogeneous, you can end up with an imbalance."
                 *
                 *  The time taken by individual compile jobs here can vary a
                 *  lot, depending on various factors like file size. This can
                 *  create an imbalance, like mentioned above, and we can end up
                 *  in a situation where one of the partitions has a job that
                 *  takes very long to execute, by which time other partitions
                 *  have completed, so some cores are idle.  But the idle
                 *  ones won't get any of the remaining jobs, because they are
                 *  all assigned to that one partition.
                 *
                 *  Instead, we want to use work-stealing so jobs can be run by any partition.
                 */
                ParallelLoopResult result = Parallel.ForEach(
                    Partitioner.Create(filesToCompile, EnumerablePartitionerOptions.NoBuffering),
                    new ParallelOptions {
                    MaxDegreeOfParallelism = allowedParallelism
                },
                    (toCompile, state) =>
                {
                    if (!ProcessSourceFile(toCompile.Item1, toCompile.Item2))
                    {
                        state.Stop();
                    }
                });

                if (!result.IsCompleted && !Log.HasLoggedErrors)
                {
                    Log.LogError("Unknown failure occurred while compiling. Check logs to get more details.");
                }

                if (!Log.HasLoggedErrors)
                {
                    int numUnchanged = _totalFiles - _numCompiled;
                    if (numUnchanged > 0)
                    {
                        Log.LogMessage(MessageImportance.High, $"[{numUnchanged}/{_totalFiles}] unchanged.");
                    }
                }
            }
            finally
            {
                if (!string.IsNullOrEmpty(_tempPath))
                {
                    Directory.Delete(_tempPath, true);
                }
            }

            OutputFiles = outputItems.ToArray();
            return(!Log.HasLoggedErrors);

            bool ProcessSourceFile(string srcFile, string objFile)
            {
                string tmpObjFile = Path.GetTempFileName();

                try
                {
                    string command   = $"emcc {Arguments} -c -o \"{tmpObjFile}\" \"{srcFile}\"";
                    var    startTime = DateTime.Now;

                    // Log the command in a compact format which can be copy pasted
                    StringBuilder envStr = new StringBuilder(string.Empty);
                    foreach (var key in envVarsDict.Keys)
                    {
                        envStr.Append($"{key}={envVarsDict[key]} ");
                    }
                    Log.LogMessage(MessageImportance.Low, $"Exec: {envStr}{command}");
                    (int exitCode, string output) = Utils.RunShellCommand(
                        Log,
                        command,
                        envVarsDict,
                        workingDir: Environment.CurrentDirectory,
                        logStdErrAsMessage: true,
                        debugMessageImportance: messageImportance,
                        label: Path.GetFileName(srcFile));

                    var endTime     = DateTime.Now;
                    var elapsedSecs = (endTime - startTime).TotalSeconds;
                    if (exitCode != 0)
                    {
                        Log.LogError($"Failed to compile {srcFile} -> {objFile}{Environment.NewLine}{output} [took {elapsedSecs:F}s]");
                        return(false);
                    }

                    if (!Utils.CopyIfDifferent(tmpObjFile, objFile, useHash: true))
                    {
                        Log.LogMessage(MessageImportance.Low, $"Did not overwrite {objFile} as the contents are unchanged");
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Low, $"Copied {tmpObjFile} to {objFile}");
                    }

                    outputItems.Add(CreateOutputItemFor(srcFile, objFile));

                    int count = Interlocked.Increment(ref _numCompiled);
                    Log.LogMessage(MessageImportance.High, $"[{count}/{_totalFiles}] {Path.GetFileName(srcFile)} -> {Path.GetFileName(objFile)} [took {elapsedSecs:F}s]");

                    return(!Log.HasLoggedErrors);
                }
                catch (Exception ex)
                {
                    Log.LogError($"Failed to compile {srcFile} -> {objFile}{Environment.NewLine}{ex.Message}");
                    return(false);
                }
                finally
                {
                    File.Delete(tmpObjFile);
                }
            }

            ITaskItem CreateOutputItemFor(string srcFile, string objFile)
            {
                ITaskItem newItem = new TaskItem(objFile);

                newItem.SetMetadata("SourceFile", srcFile);
                return(newItem);
            }
        }
Пример #6
0
        public override bool Execute()
        {
            if (SourceFiles.Length == 0)
            {
                Log.LogError($"No SourceFiles to compile");
                return(false);
            }

            ITaskItem?badItem = SourceFiles.FirstOrDefault(sf => string.IsNullOrEmpty(sf.GetMetadata("ObjectFile")));

            if (badItem != null)
            {
                Log.LogError($"Source file {badItem.ItemSpec} is missing ObjectFile metadata.");
                return(false);
            }

            if (!Enum.TryParse(OutputMessageImportance, ignoreCase: true, out MessageImportance messageImportance))
            {
                Log.LogError($"Invalid value for OutputMessageImportance={OutputMessageImportance}. Valid values: {string.Join(", ", Enum.GetNames(typeof(MessageImportance)))}");
                return(false);
            }

            _totalFiles = SourceFiles.Length;
            IDictionary <string, string> envVarsDict = GetEnvironmentVariablesDict();
            ConcurrentBag <ITaskItem>    outputItems = new();

            try
            {
                List <(string, string)> filesToCompile = new();
                foreach (ITaskItem srcItem in SourceFiles)
                {
                    string   srcFile     = srcItem.ItemSpec;
                    string   objFile     = srcItem.GetMetadata("ObjectFile");
                    string   depMetadata = srcItem.GetMetadata("Dependencies");
                    string[] depFiles    = string.IsNullOrEmpty(depMetadata)
                                            ? Array.Empty <string>()
                                            : depMetadata.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    if (!ShouldCompile(srcFile, objFile, depFiles, out string reason))
                    {
                        Log.LogMessage(MessageImportance.Low, $"Skipping {srcFile} because {reason}.");
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Low, $"Compiling {srcFile} because {reason}.");
                        filesToCompile.Add((srcFile, objFile));
                    }
                }

                _numCompiled = SourceFiles.Length - filesToCompile.Count;
                if (_numCompiled == _totalFiles)
                {
                    // nothing to do!
                    return(true);
                }

                if (_numCompiled > 0)
                {
                    Log.LogMessage(MessageImportance.High, $"[{_numCompiled}/{SourceFiles.Length}] skipped unchanged files");
                }

                Log.LogMessage(MessageImportance.Low, "Using environment variables:");
                foreach (var kvp in envVarsDict)
                {
                    Log.LogMessage(MessageImportance.Low, $"\t{kvp.Key} = {kvp.Value}");
                }

                string workingDir = Environment.CurrentDirectory;
                Log.LogMessage(MessageImportance.Low, $"Using working directory: {workingDir}");

                _tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(_tempPath);

                int allowedParallelism = Math.Min(SourceFiles.Length, Environment.ProcessorCount);
                if (BuildEngine is IBuildEngine9 be9)
                {
                    allowedParallelism = be9.RequestCores(allowedParallelism);
                }

                if (DisableParallelCompile || allowedParallelism == 1)
                {
                    foreach ((string srcFile, string outFile) in filesToCompile)
                    {
                        if (!ProcessSourceFile(srcFile, outFile))
                        {
                            return(false);
                        }
                    }
                }
                else
                {
                    ParallelLoopResult result = Parallel.ForEach(filesToCompile,
                                                                 new ParallelOptions {
                        MaxDegreeOfParallelism = allowedParallelism
                    },
                                                                 (toCompile, state) =>
                    {
                        if (!ProcessSourceFile(toCompile.Item1, toCompile.Item2))
                        {
                            state.Stop();
                        }
                    });

                    if (!result.IsCompleted && !Log.HasLoggedErrors)
                    {
                        Log.LogError("Unknown failed occured while compiling");
                    }
                }

                if (!Log.HasLoggedErrors)
                {
                    int numUnchanged = _totalFiles - _numCompiled;
                    if (numUnchanged > 0)
                    {
                        Log.LogMessage(MessageImportance.High, $"[{numUnchanged}/{_totalFiles}] unchanged.");
                    }
                }
            }
            finally
            {
                if (!string.IsNullOrEmpty(_tempPath))
                {
                    Directory.Delete(_tempPath, true);
                }
            }

            OutputFiles = outputItems.ToArray();
            return(!Log.HasLoggedErrors);

            bool ProcessSourceFile(string srcFile, string objFile)
            {
                string tmpObjFile = Path.GetTempFileName();

                try
                {
                    string command   = $"emcc {Arguments} -c -o \"{tmpObjFile}\" \"{srcFile}\"";
                    var    startTime = DateTime.Now;

                    // Log the command in a compact format which can be copy pasted
                    StringBuilder envStr = new StringBuilder(string.Empty);
                    foreach (var key in envVarsDict.Keys)
                    {
                        envStr.Append($"{key}={envVarsDict[key]} ");
                    }
                    Log.LogMessage(MessageImportance.Low, $"Exec: {envStr}{command}");
                    (int exitCode, string output) = Utils.RunShellCommand(
                        Log,
                        command,
                        envVarsDict,
                        workingDir: Environment.CurrentDirectory,
                        logStdErrAsMessage: true,
                        debugMessageImportance: messageImportance,
                        label: Path.GetFileName(srcFile));

                    var endTime     = DateTime.Now;
                    var elapsedSecs = (endTime - startTime).TotalSeconds;
                    if (exitCode != 0)
                    {
                        Log.LogError($"Failed to compile {srcFile} -> {objFile}{Environment.NewLine}{output} [took {elapsedSecs:F}s]");
                        return(false);
                    }

                    if (!Utils.CopyIfDifferent(tmpObjFile, objFile, useHash: true))
                    {
                        Log.LogMessage(MessageImportance.Low, $"Did not overwrite {objFile} as the contents are unchanged");
                    }
                    else
                    {
                        Log.LogMessage(MessageImportance.Low, $"Copied {tmpObjFile} to {objFile}");
                    }

                    ITaskItem newItem = new TaskItem(objFile);
                    newItem.SetMetadata("SourceFile", srcFile);
                    outputItems.Add(newItem);

                    int count = Interlocked.Increment(ref _numCompiled);
                    Log.LogMessage(MessageImportance.High, $"[{count}/{_totalFiles}] {Path.GetFileName(srcFile)} -> {Path.GetFileName(objFile)} [took {elapsedSecs:F}s]");

                    return(!Log.HasLoggedErrors);
                }
                catch (Exception ex)
                {
                    Log.LogError($"Failed to compile {srcFile} -> {objFile}{Environment.NewLine}{ex.Message}");
                    return(false);
                }
                finally
                {
                    File.Delete(tmpObjFile);
                }
            }
        }
Пример #7
0
 protected abstract string?BuildSourceLinkUrl(Uri contentUrl, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem);
 protected override string?BuildSourceLinkUrl(Uri contentUrl, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem)
 => $"ContentUrl='{contentUrl}' GitUrl='{gitUri}' RelativeUrl='{relativeUrl}' RevisionId='{revisionId}'";
Пример #9
0
        protected override string BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem)
        {
            var trimLeadingSlash  = relativeUrl.TrimStart('/');
            var trimmedContentUrl = contentUri.ToString().TrimEnd('/', '\\');

            // p = project/path
            // a = action
            // hb = SHA/revision
            // f = repo file path
            var gitwebRawUrl = UriUtilities.Combine(trimmedContentUrl, $"?p={trimLeadingSlash}.git;a=blob_plain;hb={revisionId};f=*");

            return(gitwebRawUrl);
        }
Пример #10
0
        public override bool Execute()
        {
            if (SourceFiles.Length == 0)
            {
                Log.LogError($"No SourceFiles to compile");
                return(false);
            }

            ITaskItem?badItem = SourceFiles.FirstOrDefault(sf => string.IsNullOrEmpty(sf.GetMetadata("ObjectFile")));

            if (badItem != null)
            {
                Log.LogError($"Source file {badItem.ItemSpec} is missing ObjectFile metadata.");
                return(false);
            }

            IDictionary <string, string> envVarsDict = GetEnvironmentVariablesDict();
            ConcurrentBag <ITaskItem>    outputItems = new();

            try
            {
                Log.LogMessage(MessageImportance.Low, "Using environment variables:");
                foreach (var kvp in envVarsDict)
                {
                    Log.LogMessage(MessageImportance.Low, $"\t{kvp.Key} = {kvp.Value}");
                }

                string workingDir = Environment.CurrentDirectory;
                Log.LogMessage(MessageImportance.Low, $"Using working directory: {workingDir}");

                _tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(_tempPath);

                int allowedParallelism = Math.Min(SourceFiles.Length, Environment.ProcessorCount);
#if false // Enable this when we bump msbuild to 16.1.0
                if (BuildEngine is IBuildEngine9 be9)
                {
                    allowedParallelism = be9.RequestCores(allowedParallelism);
                }
#endif

                if (DisableParallelCompile || allowedParallelism == 1)
                {
                    foreach (ITaskItem srcItem in SourceFiles)
                    {
                        if (!ProcessSourceFile(srcItem))
                        {
                            return(false);
                        }
                    }
                }
                else
                {
                    ParallelLoopResult result = Parallel.ForEach(SourceFiles,
                                                                 new ParallelOptions {
                        MaxDegreeOfParallelism = allowedParallelism
                    },
                                                                 (srcItem, state) =>
                    {
                        if (!ProcessSourceFile(srcItem))
                        {
                            state.Stop();
                        }
                    });

                    if (!result.IsCompleted && !Log.HasLoggedErrors)
                    {
                        Log.LogError("Unknown failed occured while compiling");
                    }
                }
            }
            finally
            {
                if (!string.IsNullOrEmpty(_tempPath))
                {
                    Directory.Delete(_tempPath, true);
                }
            }

            OutputFiles = outputItems.ToArray();
            return(!Log.HasLoggedErrors);

            bool ProcessSourceFile(ITaskItem srcItem)
            {
                string srcFile = srcItem.ItemSpec;
                string objFile = srcItem.GetMetadata("ObjectFile");

                try
                {
                    string command = $"emcc {Arguments} -c -o {objFile} {srcFile}";

                    // Log the command in a compact format which can be copy pasted
                    StringBuilder envStr = new StringBuilder(string.Empty);
                    foreach (var key in envVarsDict.Keys)
                    {
                        envStr.Append($"{key}={envVarsDict[key]} ");
                    }
                    Log.LogMessage(MessageImportance.Low, $"Exec: {envStr}{command}");
                    (int exitCode, string output) = Utils.RunShellCommand(command, envVarsDict, workingDir: Environment.CurrentDirectory);

                    if (exitCode != 0)
                    {
                        Log.LogError($"Failed to compile {srcFile} -> {objFile}{Environment.NewLine}{output}");
                        return(false);
                    }

                    ITaskItem newItem = new TaskItem(objFile);
                    newItem.SetMetadata("SourceFile", srcFile);
                    outputItems.Add(newItem);

                    return(true);
                }
                catch (Exception ex)
                {
                    Log.LogError($"Failed to compile {srcFile} -> {objFile}{Environment.NewLine}{ex.Message}");
                    return(false);
                }
            }
        }
Пример #11
0
 protected override string?BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem)
 => UriUtilities.Combine(UriUtilities.Combine(contentUri.ToString(), relativeUrl), revisionId + "/*");
Пример #12
0
        protected override string?BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem)
        {
            // The SourceLinkBitbucketGitHost item for bitbucket.org specifies EnterpriseEdition="false".
            // Other items that may be specified by the project default to EnterpriseEdition="true" without specifying it.
            bool isCloud = bool.TryParse(hostItem?.GetMetadata(IsEnterpriseEditionMetadataName), out var isEnterpriseEdition) && !isEnterpriseEdition;

            if (isCloud)
            {
                return(BuildSourceLinkUrlForCloudEdition(contentUri, relativeUrl, revisionId));
            }

            if (TryParseEnterpriseUrl(relativeUrl, out var relativeBaseUrl, out var projectName, out var repositoryName))
            {
                var version = GetBitbucketEnterpriseVersion(hostItem);
                return(BuildSourceLinkUrlForEnterpriseEdition(contentUri, relativeBaseUrl, projectName, repositoryName, revisionId, version));
            }

            Log.LogError(CommonResources.ValueOfWithIdentityIsInvalid, Names.SourceRoot.RepositoryUrlFullName, SourceRoot.ItemSpec, gitUri);
            return(null);
        }
Пример #13
0
        protected override string?BuildSourceLinkUrl(Uri contentUri, Uri gitUri, string relativeUrl, string revisionId, ITaskItem?hostItem)
        {
            var path = GetVersion(hostItem) >= s_versionWithNewUrlFormat
                ? "-/raw/" + revisionId + "/*"
                : "raw/" + revisionId + "/*";

            return(UriUtilities.Combine(UriUtilities.Combine(contentUri.ToString(), relativeUrl), path));
        }