diff --git a/src/ScmBackup/Configuration/ConfigOptions.cs b/src/ScmBackup/Configuration/ConfigOptions.cs
index a3332b0..c5029af 100644
--- a/src/ScmBackup/Configuration/ConfigOptions.cs
+++ b/src/ScmBackup/Configuration/ConfigOptions.cs
@@ -9,5 +9,24 @@ namespace ScmBackup.Configuration
///
class ConfigOptions
{
+ public ConfigOptions()
+ {
+ this.Git = new GitOptions();
+ }
+
+ public GitOptions Git { get; set; }
+ }
+
+ class GitOptions
+ {
+ ///
+ /// Git implementation that will be used for all Git operations
+ ///
+ public string Implementation { get; set; }
+
+ ///
+ /// LFS implementation for Git
+ ///
+ public bool UseLfs { get; set; }
}
-}
+}
\ No newline at end of file
diff --git a/src/ScmBackup/Scm/CommandLineScm.cs b/src/ScmBackup/Scm/CommandLineScm.cs
index cc4525f..0b8926b 100644
--- a/src/ScmBackup/Scm/CommandLineScm.cs
+++ b/src/ScmBackup/Scm/CommandLineScm.cs
@@ -33,6 +33,11 @@ internal abstract class CommandLineScm : IScm
///
public abstract string GetVersionNumber();
+ ///
+ /// Checks whether git lfs is installed on this computer
+ ///
+ public abstract bool LFSIsOnThisComputer();
+
///
/// Executes the command line tool.
///
@@ -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;
}
@@ -102,6 +124,16 @@ public void PullFromRemote(string remoteUrl, string directory)
///
public abstract void PullFromRemote(string remoteUrl, string directory, ScmCredentials credentials);
+ ///
+ /// Pulls LFS files from a remote repository into a local folder.
+ ///
+ public abstract void PullLFSFromRemote(string remoteUrl, string directory, ScmCredentials credentials);
+
+ ///
+ /// Checks whether the repo contains LFS files
+ ///
+ public abstract bool RepositoryContainsLFS(string directory);
+
///
/// 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.
@@ -138,5 +170,6 @@ private void GetExecutable()
}
}
}
+
}
}
diff --git a/src/ScmBackup/Scm/GitScm.cs b/src/ScmBackup/Scm/GitScm.cs
index 9eb2150..04476da 100644
--- a/src/ScmBackup/Scm/GitScm.cs
+++ b/src/ScmBackup/Scm/GitScm.cs
@@ -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
@@ -103,7 +117,7 @@ public override void PullFromRemote(string remoteUrl, string directory, ScmCrede
{
throw new InvalidOperationException(string.Format(Resource.ScmTargetDirectoryNotEmpty, directory));
}
-
+
this.CreateRepository(directory);
}
@@ -111,7 +125,7 @@ public override void PullFromRemote(string remoteUrl, string directory, ScmCrede
{
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);
@@ -119,6 +133,51 @@ public override void PullFromRemote(string remoteUrl, string directory, ScmCrede
{
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)
@@ -154,4 +213,4 @@ public string CreateRepoUrlWithCredentials(string url, ScmCredentials credential
return uri.ToString();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ScmBackup/Scm/IScm.cs b/src/ScmBackup/Scm/IScm.cs
index f3def49..105043b 100644
--- a/src/ScmBackup/Scm/IScm.cs
+++ b/src/ScmBackup/Scm/IScm.cs
@@ -25,6 +25,11 @@ internal interface IScm
///
string GetVersionNumber();
+ ///
+ /// Checks whether the git LFS is present on this computer
+ ///
+ bool LFSIsOnThisComputer();
+
///
/// Checks whether the given directory is a repository
///
@@ -57,9 +62,20 @@ internal interface IScm
///
void PullFromRemote(string remoteUrl, string directory, ScmCredentials credentials);
+ ///
+ /// Pulls all LFS files from a remote repository into a local folder.
+ ///
+ void PullLFSFromRemote(string remoteUrl, string directory, ScmCredentials credentials);
+
+ ///
+ /// Checks whether the repo in this directory contains LFS files
+ ///
+ bool RepositoryContainsLFS(string directory);
+
///
/// Checks whether the repo in this directory contains a commit with this ID
///
bool RepositoryContainsCommit(string directory, string commitid);
+
}
}
diff --git a/src/ScmBackup/Scm/MercurialScm.cs b/src/ScmBackup/Scm/MercurialScm.cs
index 7e187f0..ce4adcf 100644
--- a/src/ScmBackup/Scm/MercurialScm.cs
+++ b/src/ScmBackup/Scm/MercurialScm.cs
@@ -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");
@@ -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).
@@ -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);
}
+
}
}