예제 #1
0
        private TempDirectory(string path, TempRoot root)
        {
            NullableDebug.Assert(path != null);
            NullableDebug.Assert(root != null);

            _path = path;
            _root = root;
        }
예제 #2
0
            public Reader(string gitDirectory, string commonDirectory, GitEnvironment environment, Func <string, TextReader>?fileOpener = null)
            {
                NullableDebug.Assert(environment != null);

                _environment       = environment;
                _gitDirectoryPosix = PathUtils.ToPosixDirectoryPath(gitDirectory);
                _commonDirectory   = commonDirectory;
                _fileOpener        = fileOpener ?? File.OpenText;
            }
예제 #3
0
        internal GitIgnore(PatternGroup?root, string workingDirectory, bool ignoreCase)
        {
            NullableDebug.Assert(PathUtils.IsAbsolute(workingDirectory));

            IgnoreCase               = ignoreCase;
            WorkingDirectory         = PathUtils.ToPosixDirectoryPath(workingDirectory);
            _workingDirectoryNoSlash = PathUtils.TrimTrailingSlash(WorkingDirectory);
            Root = root;
        }
예제 #4
0
            public PatternGroup(PatternGroup?parent, string containingDirectory, ImmutableArray <Pattern> patterns)
            {
                NullableDebug.Assert(PathUtils.IsPosixPath(containingDirectory));
                NullableDebug.Assert(PathUtils.HasTrailingSlash(containingDirectory));

                Parent = parent;
                ContainingDirectory = containingDirectory;
                Patterns            = patterns;
            }
예제 #5
0
        internal static Uri?NormalizeUrl(GitRepository repository, string url)
        {
            // Git (v2.23.0) treats local relative URLs as relative to the working directory.
            // This doesn't work when a relative URL is used in a config file locatede in a main .git directory
            // but is resolved from a worktree that has a different working directory.
            // Currently we implement the same behavior as git.

            NullableDebug.Assert(repository.WorkingDirectory != null);
            return(NormalizeUrl(ApplyInsteadOfUrlMapping(repository.Config, url), root: repository.WorkingDirectory));
        }
예제 #6
0
        internal GitRepositoryLocation(string gitDirectory, string commonDirectory, string?workingDirectory)
        {
            NullableDebug.Assert(PathUtils.IsNormalized(gitDirectory));
            NullableDebug.Assert(PathUtils.IsNormalized(commonDirectory));
            NullableDebug.Assert(workingDirectory == null || PathUtils.IsNormalized(workingDirectory));

            GitDirectory     = gitDirectory;
            CommonDirectory  = commonDirectory;
            WorkingDirectory = workingDirectory;
        }
예제 #7
0
        public GitVariableName(string sectionName, string subsectionName, string variableName)
        {
            NullableDebug.Assert(sectionName != null);
            NullableDebug.Assert(subsectionName != null);
            NullableDebug.Assert(variableName != null);

            SectionName    = sectionName;
            SubsectionName = subsectionName;
            VariableName   = variableName;
        }
예제 #8
0
        private protected override void Execute(GitRepository repository)
        {
            NullableDebug.Assert(repository.WorkingDirectory != null);

            RepositoryId     = repository.GitDirectory;
            WorkingDirectory = repository.WorkingDirectory;
            Url        = GitOperations.GetRepositoryUrl(repository, RemoteName, Log.LogWarning);
            Roots      = GitOperations.GetSourceRoots(repository, RemoteName, Log.LogWarning);
            RevisionId = repository.GetHeadCommitSha();
        }
예제 #9
0
        internal GitSubmodule(string name, string workingDirectoryRelativePath, string workingDirectoryFullPath, string?url, string?headCommitSha)
        {
            NullableDebug.Assert(name != null);
            NullableDebug.Assert(workingDirectoryRelativePath != null);
            NullableDebug.Assert(workingDirectoryFullPath != null);

            Name = name;
            WorkingDirectoryRelativePath = workingDirectoryRelativePath;
            WorkingDirectoryFullPath     = workingDirectoryFullPath;
            Url           = url;
            HeadCommitSha = headCommitSha;
        }
예제 #10
0
        public static bool TryParseHostedSsh(Uri uri, [NotNullWhen(true)] out string?account, [NotNullWhen(true)] out string?repositoryPath, [NotNullWhen(true)] out string?repositoryName)
        {
            NullableDebug.Assert(uri != null);

            account = repositoryPath = repositoryName = null;

            // {"DefaultCollection"|""}/{repositoryPath}/"_ssh"/{"_full"|"_optimized"}/{repositoryName}
            if (!UriUtilities.TrySplitRelativeUrl(uri.GetPath(), out var parts) || parts.Length == 0)
            {
                return(false);
            }

            // Check for v3 url format
            if (parts[0] == "v3" &&
                parts.Length >= 3 &&
                TryParsePath(parts, 2, type: null, out repositoryPath, out repositoryName) &&
                repositoryPath != "")
            {
                // ssh://{user}@{domain}:{port}/v3/{account}/{repositoryPath}/{'_full'|'_optimized'|''}/{repositoryName}
                account = parts[1];
            }
            else
            {
                // ssh v1/v2 url formats
                // ssh://{account}@vs-ssh.visualstudio.com/

                account = uri.UserInfo;

                int index = 0;
                if (StringComparer.OrdinalIgnoreCase.Equals(parts[0], "DefaultCollection"))
                {
                    index++;
                }

                if (!TryParsePath(parts, index, "_ssh", out repositoryPath, out repositoryName))
                {
                    // Failed to parse path
                    return(false);
                }
            }

            if (account.Length == 0)
            {
                return(false);
            }

            return(true);
        }
예제 #11
0
        internal static DirectoryNode BuildDirectoryTree(GitRepository repository, Func <GitEnvironment, string, GitRepository?> repositoryFactory)
        {
            NullableDebug.Assert(repository.WorkingDirectory != null);

            var treeRoot = new DirectoryNode(name: "", new List <DirectoryNode>());

            AddTreeNode(treeRoot, repository.WorkingDirectory, new Lazy <GitIgnore.Matcher?>(() => repository.Ignore.CreateMatcher()));

            foreach (var submodule in repository.GetSubmodules())
            {
                var submoduleWorkingDirectory = submodule.WorkingDirectoryFullPath;

                AddTreeNode(treeRoot, submoduleWorkingDirectory,
                            new Lazy <GitIgnore.Matcher?>(() => repositoryFactory(repository.Environment, submoduleWorkingDirectory)?.Ignore.CreateMatcher()));
            }

            return(treeRoot);
        }
예제 #12
0
        private static string?GetRepositoryUrl(GitRepository repository, string?remoteName, int recursionDepth, Action <string, object?[]>?logWarning = null)
        {
            NullableDebug.Assert(repository.WorkingDirectory != null);

            var remoteUrl = GetRemoteUrl(repository, ref remoteName, logWarning);

            if (remoteUrl == null)
            {
                return(null);
            }

            var uri = NormalizeUrl(repository, remoteUrl);

            if (uri == null)
            {
                logWarning?.Invoke(Resources.InvalidRepositoryRemoteUrl, new[] { remoteName, remoteUrl });
                return(null);
            }

            return(ResolveUrl(uri, repository.Environment, remoteName, recursionDepth, logWarning));
        }
예제 #13
0
 public GitConfig(ImmutableDictionary <GitVariableName, ImmutableArray <string> > variables)
 {
     NullableDebug.Assert(variables != null);
     Variables = variables;
 }
예제 #14
0
        public static ITaskItem[] GetSourceRoots(GitRepository repository, string?remoteName, Action <string, object?[]> logWarning)
        {
            // Not supported for repositories without a working directory.
            NullableDebug.Assert(repository.WorkingDirectory != null);

            var result   = new List <TaskItem>();
            var repoRoot = repository.WorkingDirectory.EndWithSeparator();

            var revisionId = repository.GetHeadCommitSha();

            if (revisionId != null)
            {
                // Don't report a warning since it has already been reported by GetRepositoryUrl task.
                string?repositoryUrl = GetRepositoryUrl(repository, remoteName, logWarning: null);

                // Item metadata are stored msbuild-escaped. GetMetadata unescapes, SetMetadata stores the value as specified.
                // Escape msbuild special characters so that URL escapes in the URL are preserved when the URL is read by GetMetadata.

                var item = new TaskItem(Evaluation.ProjectCollection.Escape(repoRoot));
                item.SetMetadata(Names.SourceRoot.SourceControl, SourceControlName);
                item.SetMetadata(Names.SourceRoot.ScmRepositoryUrl, Evaluation.ProjectCollection.Escape(repositoryUrl));
                item.SetMetadata(Names.SourceRoot.RevisionId, revisionId);
                result.Add(item);
            }
            else
            {
                logWarning(Resources.RepositoryHasNoCommit, Array.Empty <object>());
            }

            foreach (var submodule in repository.GetSubmodules())
            {
                var commitSha = submodule.HeadCommitSha;
                if (commitSha == null)
                {
                    logWarning(Resources.SourceCodeWontBeAvailableViaSourceLink,
                               new[] { string.Format(Resources.SubmoduleWithoutCommit, new[] { submodule.Name }) });

                    continue;
                }

                // submodule.<name>.url specifies where to find the submodule.
                // This variable is calculated based on the entry in .gitmodules by git submodule init and will be present for initialized submodules.
                // Uninitialized modules don't have source that should be considered during the build.
                // Relative URLs are relative to the repository directory.
                // See https://git-scm.com/docs/gitsubmodules.
                var submoduleConfigUrl = repository.Config.GetVariableValue(SubmoduleSectionName, submodule.Name, UrlVariableName);
                if (submoduleConfigUrl == null)
                {
                    continue;
                }

                var submoduleUri = NormalizeUrl(repository, submoduleConfigUrl);
                if (submoduleUri == null)
                {
                    logWarning(Resources.SourceCodeWontBeAvailableViaSourceLink,
                               new[] { string.Format(Resources.InvalidSubmoduleUrl, submodule.Name, submoduleConfigUrl) });

                    continue;
                }

                var submoduleUrl = ResolveUrl(submoduleUri, repository.Environment, remoteName, recursionDepth: 0, logWarning);
                if (submoduleUrl == null)
                {
                    logWarning(Resources.SourceCodeWontBeAvailableViaSourceLink,
                               new[] { string.Format(Resources.InvalidSubmoduleUrl, submodule.Name, submoduleConfigUrl) });

                    continue;
                }

                // Item metadata are stored msbuild-escaped. GetMetadata unescapes, SetMetadata stores the value as specified.
                // Escape msbuild special characters so that URL escapes and non-ascii characters in the URL and paths are
                // preserved when read by GetMetadata.

                var item = new TaskItem(Evaluation.ProjectCollection.Escape(submodule.WorkingDirectoryFullPath.EndWithSeparator()));
                item.SetMetadata(Names.SourceRoot.SourceControl, SourceControlName);
                item.SetMetadata(Names.SourceRoot.ScmRepositoryUrl, Evaluation.ProjectCollection.Escape(submoduleUrl));
                item.SetMetadata(Names.SourceRoot.RevisionId, commitSha);
                item.SetMetadata(Names.SourceRoot.ContainingRoot, Evaluation.ProjectCollection.Escape(repoRoot));
                item.SetMetadata(Names.SourceRoot.NestedRoot, Evaluation.ProjectCollection.Escape(submodule.WorkingDirectoryRelativePath.EndWithSeparator('/')));
                result.Add(item);
            }

            foreach (var diagnostic in repository.GetSubmoduleDiagnostics())
            {
                logWarning(Resources.SourceCodeWontBeAvailableViaSourceLink, new[] { diagnostic });
            }

            return(result.ToArray());
        }