Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/ScmBackup/Configuration/ConfigOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,24 @@ namespace ScmBackup.Configuration
/// </summary>
class ConfigOptions
{
public ConfigOptions()
{
this.Git = new GitOptions();
}

public GitOptions Git { get; set; }
}

class GitOptions
{
/// <summary>
/// Git implementation that will be used for all Git operations
/// </summary>
public string Implementation { get; set; }

/// <summary>
/// LFS implementation for Git
/// </summary>
public bool UseLfs { get; set; }
}
}
}
37 changes: 35 additions & 2 deletions src/ScmBackup/Scm/CommandLineScm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ internal abstract class CommandLineScm : IScm
/// </summary>
public abstract string GetVersionNumber();

/// <summary>
/// Checks whether git lfs is installed on this computer
/// </summary>
public abstract bool LFSIsOnThisComputer();

/// <summary>
/// Executes the command line tool.
/// </summary>
Expand All @@ -50,12 +55,29 @@ protected CommandLineResult ExecuteCommand(string args)
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;

//var proc = Process.Start(info);
//var result = new CommandLineResult();
//result.StandardError = proc.StandardError.ReadToEnd();
//result.StandardOutput = proc.StandardOutput.ReadToEnd();
//proc.WaitForExit();

//result.ExitCode = proc.ExitCode;
//return result;

//deadlock fix to make function 'RepositoryContainsLFS' run without deadlock
var proc = Process.Start(info);
var result = new CommandLineResult();
result.StandardError = proc.StandardError.ReadToEnd();
result.StandardOutput = proc.StandardOutput.ReadToEnd();
var output = new System.Text.StringBuilder();
var error = new System.Text.StringBuilder();

proc.OutputDataReceived += (sender, eventArgs) => output.AppendLine(eventArgs.Data);
proc.ErrorDataReceived += (sender, eventArgs) => error.AppendLine(eventArgs.Data);
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();

result.StandardOutput = output.ToString();
result.StandardError = error.ToString();
result.ExitCode = proc.ExitCode;
return result;
}
Expand Down Expand Up @@ -102,6 +124,16 @@ public void PullFromRemote(string remoteUrl, string directory)
/// </summary>
public abstract void PullFromRemote(string remoteUrl, string directory, ScmCredentials credentials);

/// <summary>
/// Pulls LFS files from a remote repository into a local folder.
/// </summary>
public abstract void PullLFSFromRemote(string remoteUrl, string directory, ScmCredentials credentials);

/// <summary>
/// Checks whether the repo contains LFS files
/// </summary>
public abstract bool RepositoryContainsLFS(string directory);

/// <summary>
/// Checks whether the repo in this directory contains a commit with this ID
/// Must be implemented in the child classes by calling ExecuteCommand and checking the result.
Expand Down Expand Up @@ -138,5 +170,6 @@ private void GetExecutable()
}
}
}

}
}
65 changes: 62 additions & 3 deletions src/ScmBackup/Scm/GitScm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ public override string GetVersionNumber()
throw new InvalidOperationException(result.Output);
}

public override bool LFSIsOnThisComputer()
{
var result = this.ExecuteCommand("lfs version");

if (result.Successful)
{
return true; //git lfs found: run lfs commands
}
else
{
return false; //git lfs not found: do not run lfs commands
}
}

public override bool DirectoryIsRepository(string directory)
{
// SCM Backup uses bare repos only, so we don't need to check for non-bare repos at all
Expand Down Expand Up @@ -103,22 +117,67 @@ public override void PullFromRemote(string remoteUrl, string directory, ScmCrede
{
throw new InvalidOperationException(string.Format(Resource.ScmTargetDirectoryNotEmpty, directory));
}

this.CreateRepository(directory);
}

if (credentials != null)
{
remoteUrl = this.CreateRepoUrlWithCredentials(remoteUrl, credentials);
}

string cmd = string.Format("-C \"{0}\" fetch --force --prune {1} refs/heads/*:refs/heads/* refs/tags/*:refs/tags/*", directory, remoteUrl);
var result = this.ExecuteCommand(cmd);

if (!result.Successful)
{
throw new InvalidOperationException(result.Output);
}

if (LFSIsOnThisComputer())
{
if (RepositoryContainsLFS(directory))
{
PullLFSFromRemote(remoteUrl, directory, credentials);
}
}
}

public override void PullLFSFromRemote(string remoteUrl, string directory, ScmCredentials credentials)
{
if (credentials != null)
{
remoteUrl = this.CreateRepoUrlWithCredentials(remoteUrl, credentials);
}

string cmd = string.Format("-C \"{0}\" lfs fetch --all {1}", directory, remoteUrl); // git -C *DIR* lfs fetch --all *REMOTE*
var result = this.ExecuteCommand(cmd);

if (!result.Successful)
{
throw new InvalidOperationException(result.Output);
}
}

public override bool RepositoryContainsLFS(string directory) //test if repo contains lfs files
{
//do not run if LFSIsOnThisComputer = false
string cmd = string.Format("-C \"{0}\" lfs ls-files", directory);
var result = this.ExecuteCommand(cmd);

if (!result.Successful)
{
throw new InvalidOperationException(result.Output);
}

if (String.IsNullOrWhiteSpace(result.Output))
{
return false; //no lfs files found, continuing
}
else
{
return true; //lfs files found, backing them up
}
}

public override bool RepositoryContainsCommit(string directory, string commitid)
Expand Down Expand Up @@ -154,4 +213,4 @@ public string CreateRepoUrlWithCredentials(string url, ScmCredentials credential
return uri.ToString();
}
}
}
}
16 changes: 16 additions & 0 deletions src/ScmBackup/Scm/IScm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ internal interface IScm
/// </summary>
string GetVersionNumber();

/// <summary>
/// Checks whether the git LFS is present on this computer
/// </summary>
bool LFSIsOnThisComputer();

/// <summary>
/// Checks whether the given directory is a repository
/// </summary>
Expand Down Expand Up @@ -57,9 +62,20 @@ internal interface IScm
/// </summary>
void PullFromRemote(string remoteUrl, string directory, ScmCredentials credentials);

/// <summary>
/// Pulls all LFS files from a remote repository into a local folder.
/// </summary>
void PullLFSFromRemote(string remoteUrl, string directory, ScmCredentials credentials);

/// <summary>
/// Checks whether the repo in this directory contains LFS files
/// </summary>
bool RepositoryContainsLFS(string directory);

/// <summary>
/// Checks whether the repo in this directory contains a commit with this ID
/// </summary>
bool RepositoryContainsCommit(string directory, string commitid);

}
}
16 changes: 16 additions & 0 deletions src/ScmBackup/Scm/MercurialScm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public override string GetVersionNumber()
throw new InvalidOperationException(result.Output);
}

public override bool LFSIsOnThisComputer()
{
return false;
}

public override bool DirectoryIsRepository(string directory)
{
string hgdir = Path.Combine(directory, ".hg");
Expand Down Expand Up @@ -141,6 +146,16 @@ public override bool RepositoryContainsCommit(string directory, string commitid)
return false;
}

public override void PullLFSFromRemote(string remoteUrl, string directory, ScmCredentials credentials)
{
throw new NotImplementedException();
}

public override bool RepositoryContainsLFS(string directory)
{
return false;
}

private string RemoveCredentialsFromUrl(string url, ScmCredentials credentials)
{
// Issue #19: if credentials are passed via --config, remove the username from the URL (the Bitbucket API returns the clone URL with username, for example).
Expand All @@ -164,5 +179,6 @@ private string CreateParametersWithCredentials(ScmCredentials credentials, strin

return string.Format(" --config auth.x.prefix={0} --config auth.x.username={1} --config auth.x.password={2}", baseurl, credentials.User, credentials.Password);
}

}
}