Files
git-tfs/GitTfs/Commands/Init.cs
T
Philippe Miossec 904ae3dce0 Add .gitignore support when cloning a tfs repository
by:
* committing (as a first commit in the repository) a .gitignore file based on an external template
* preventing an ignored file to be downloaded
* make it works with `init` + `fetch` and `clone` commands
2016-10-31 16:35:33 +01:00

231 lines
8.1 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using NDesk.Options;
using Sep.Git.Tfs.Core;
using StructureMap;
namespace Sep.Git.Tfs.Commands
{
[Pluggable("init")]
[Description("init [options] tfs-url-or-instance-name repository-path [git-repository]")]
public class Init : GitTfsCommand
{
private readonly InitOptions _initOptions;
private readonly RemoteOptions _remoteOptions;
private readonly Globals _globals;
private readonly IGitHelpers _gitHelper;
public Init(RemoteOptions remoteOptions, InitOptions initOptions, Globals globals, IGitHelpers gitHelper)
{
_remoteOptions = remoteOptions;
_gitHelper = gitHelper;
_globals = globals;
_initOptions = initOptions;
}
public OptionSet OptionSet
{
get { return _initOptions.OptionSet.Merge(_remoteOptions.OptionSet); }
}
public bool IsBare
{
get { return _initOptions.IsBare; }
}
public IGitHelpers GitHelper
{
get { return _gitHelper; }
}
public int Run(string tfsUrl, string tfsRepositoryPath)
{
tfsRepositoryPath.AssertValidTfsPathOrRoot();
DoGitInitDb();
CommitTheGitIgnoreFile(_initOptions.GitIgnorePath);
GitTfsInit(tfsUrl, tfsRepositoryPath);
return 0;
}
private void CommitTheGitIgnoreFile(string pathToGitIgnoreFile)
{
if (string.IsNullOrWhiteSpace(pathToGitIgnoreFile))
{
Trace.WriteLine("No .gitignore file specified...");
return;
}
_globals.Repository.CommitGitIgnore(pathToGitIgnoreFile);
}
public int Run(string tfsUrl, string tfsRepositoryPath, string gitRepositoryPath)
{
tfsRepositoryPath.AssertValidTfsPathOrRoot();
if (!_initOptions.IsBare)
{
InitSubdir(gitRepositoryPath);
}
else
{
Environment.CurrentDirectory = gitRepositoryPath;
_globals.GitDir = ".";
}
var runResult = Run(tfsUrl, tfsRepositoryPath);
try
{
File.WriteAllText(@".git\description", tfsRepositoryPath + "\n" + HideUserCredentials(_globals.CommandLineRun));
}
catch (Exception)
{
Trace.WriteLine("warning: Unable to update de repository description!");
}
return runResult;
}
public static string HideUserCredentials(string commandLineRun)
{
Regex rgx = new Regex("(--username|-u)[= ][^ ]+");
commandLineRun = rgx.Replace(commandLineRun, "--username=xxx");
rgx = new Regex("(--password|-p)[= ][^ ]+");
return rgx.Replace(commandLineRun, "--password=xxx");
}
private void InitSubdir(string repositoryPath)
{
if (!Directory.Exists(repositoryPath))
Directory.CreateDirectory(repositoryPath);
Environment.CurrentDirectory = repositoryPath;
_globals.GitDir = ".git";
}
private void DoGitInitDb()
{
if (!Directory.Exists(_globals.GitDir) || _initOptions.IsBare)
{
_gitHelper.CommandNoisy(BuildInitCommand());
}
_globals.Repository = _gitHelper.MakeRepository(_globals.GitDir);
if (!string.IsNullOrWhiteSpace(_initOptions.WorkspacePath))
{
Trace.WriteLine("workspace path:" + _initOptions.WorkspacePath);
try
{
Directory.CreateDirectory(_initOptions.WorkspacePath);
_globals.Repository.SetConfig(GitTfsConstants.WorkspaceConfigKey, _initOptions.WorkspacePath);
}
catch (Exception)
{
throw new GitTfsException("error: workspace path is invalid!");
}
}
_globals.Repository.SetConfig(GitTfsConstants.IgnoreBranches, false.ToString());
}
private string[] BuildInitCommand()
{
var initCommand = new List<string> { "init" };
if (_initOptions.GitInitTemplate != null)
initCommand.Add("--template=" + _initOptions.GitInitTemplate);
if (_initOptions.IsBare)
initCommand.Add("--bare");
if (_initOptions.GitInitShared is string)
initCommand.Add("--shared=" + _initOptions.GitInitShared);
else if (_initOptions.GitInitShared != null)
initCommand.Add("--shared");
return initCommand.ToArray();
}
private void GitTfsInit(string tfsUrl, string tfsRepositoryPath)
{
_globals.Repository.CreateTfsRemote(new RemoteInfo
{
Id = _globals.RemoteId,
Url = tfsUrl,
Repository = tfsRepositoryPath,
RemoteOptions = _remoteOptions,
}, _initOptions.GitInitAutoCrlf, _initOptions.GitInitIgnoreCase);
}
}
public static class Ext
{
private static readonly Regex ValidTfsPath = new Regex("^\\$/.+");
public static bool IsValidTfsPath(this string tfsPath)
{
return ValidTfsPath.IsMatch(tfsPath);
}
public static void AssertValidTfsPathOrRoot(this string tfsPath)
{
if (tfsPath == GitTfsConstants.TfsRoot)
return;
AssertValidTfsPath(tfsPath);
}
public static void AssertValidTfsPath(this string tfsPath)
{
if (!ValidTfsPath.IsMatch(tfsPath))
throw new GitTfsException("TFS repository can not be root and must start with \"$/\".", SuggestPaths(tfsPath));
}
private static IEnumerable<string> SuggestPaths(string tfsPath)
{
if (tfsPath == "$" || tfsPath == "$/")
yield return "Cloning an entire TFS repository is not supported. Try using a subdirectory of the root (e.g. $/MyProject).";
else if (tfsPath.StartsWith("$"))
yield return "Try using $/" + tfsPath.Substring(1);
else
yield return "Try using $/" + tfsPath;
}
public static string ToGitRefName(this string expectedRefName)
{
expectedRefName = Regex.Replace(expectedRefName, @"[!~$?[*^: \\]", string.Empty);
expectedRefName = expectedRefName.Replace("@{", string.Empty);
expectedRefName = expectedRefName.Replace("..", string.Empty);
expectedRefName = expectedRefName.Replace("//", string.Empty);
expectedRefName = expectedRefName.Replace("/.", "/");
expectedRefName = expectedRefName.TrimEnd('.', '/');
return expectedRefName.Trim('/');
}
public static string ToGitBranchNameFromTfsRepositoryPath(this string tfsRepositoryPath, bool includeTeamProjectName = false)
{
if (includeTeamProjectName)
{
return tfsRepositoryPath
.Replace("$/", string.Empty)
.ToGitRefName();
}
string gitBranchNameExpected = tfsRepositoryPath.IndexOf("$/") == 0
? tfsRepositoryPath.Remove(0, tfsRepositoryPath.IndexOf('/', 2) + 1)
: tfsRepositoryPath;
return gitBranchNameExpected.ToGitRefName();
}
public static string ToTfsTeamProjectRepositoryPath(this string tfsRepositoryPath)
{
if (!tfsRepositoryPath.StartsWith("$/"))
{
return tfsRepositoryPath;
}
var index = tfsRepositoryPath.IndexOf('/', 2);
return index == -1 ? tfsRepositoryPath : tfsRepositoryPath.Remove(index, tfsRepositoryPath.Length - index);
}
public static string ToLocalGitRef(this string refName)
{
return "refs/heads/" + refName;
}
}
}