Path: blob/main/extensions/copilot/src/platform/git/common/utils.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type * as vscode from 'vscode';6import { Remote } from '../vscode/git';78interface GitConfigSection {9name: string;10subSectionName?: string;11properties: { [key: string]: string };12}1314class GitConfigParser {15private static readonly _lineSeparator = /\r?\n/;1617private static readonly _propertyRegex = /^\s*(\w+)\s*=\s*"?([^"]+)"?$/;18private static readonly _sectionRegex = /^\s*\[\s*([^\]]+?)\s*(\"[^"]+\")*\]\s*$/;1920static parse(raw: string): GitConfigSection[] {21const config: { sections: GitConfigSection[] } = { sections: [] };22let section: GitConfigSection = { name: 'DEFAULT', properties: {} };2324const addSection = (section?: GitConfigSection) => {25if (!section) { return; }26config.sections.push(section);27};2829for (const line of raw.split(GitConfigParser._lineSeparator)) {30// Section31const sectionMatch = line.match(GitConfigParser._sectionRegex);32if (sectionMatch?.length === 3) {33addSection(section);34section = { name: sectionMatch[1], subSectionName: sectionMatch[2]?.replaceAll('"', ''), properties: {} };3536continue;37}3839// Property40const propertyMatch = line.match(GitConfigParser._propertyRegex);41if (propertyMatch?.length === 3 && !Object.keys(section.properties).includes(propertyMatch[1])) {42section.properties[propertyMatch[1]] = propertyMatch[2];43}44}4546addSection(section);4748return config.sections;49}50}5152export function parseGitRemotes(raw: string): Remote[] {53const remotes: Remote[] = [];5455for (const remoteSection of GitConfigParser.parse(raw).filter(s => s.name === 'remote')) {56if (remoteSection.subSectionName) {57remotes.push({58name: remoteSection.subSectionName,59fetchUrl: remoteSection.properties['url'],60pushUrl: remoteSection.properties['pushurl'] ?? remoteSection.properties['url'],61isReadOnly: false62});63}64}6566return remotes;67}6869export interface GitUriParams {70path: string;71ref: string;72submoduleOf?: string;73}7475export interface GitUriOptions {76scheme?: string;77replaceFileExtension?: boolean;78submoduleOf?: string;79}8081// As a mitigation for extensions like ESLint showing warnings and errors82// for git URIs, let's change the file extension of these uris to .git,83// when `replaceFileExtension` is true.84export function toGitUri(uri: vscode.Uri, ref: string, options: GitUriOptions = {}): vscode.Uri {85const params: GitUriParams = {86path: uri.fsPath,87ref88};8990if (options.submoduleOf) {91params.submoduleOf = options.submoduleOf;92}9394let path = uri.path;9596if (options.replaceFileExtension) {97path = `${path}.git`;98} else if (options.submoduleOf) {99path = `${path}.diff`;100}101102return uri.with({ scheme: options.scheme ?? 'git', path, query: JSON.stringify(params) });103}104105106