Skip to content

Commit

Permalink
Merge pull request #54: Initial sparse implementation
Browse files Browse the repository at this point in the history
Uses the code currently at microsoft/git#180. Covers the basics of #8.

* The default `scalar clone` runs `git sparse-checkout init` so the working directory only has files at root.

* Run `git sparse-checkout add <folders.txt` to pipe in a list of folders, and it will expand those files.

Example workflow:

```sh
$ scalar clone https://dev.azure.com/gvfs/ci/_git/ForTests
Clone parameters:
  Repo URL:     https://dev.azure.com/gvfs/ci/_git/ForTests
  Branch:       Default
  Cache Server: Default
  Local Cache:  C:\.scalarCache
  Destination:  C:\_git\test2\ForTests
Authenticating...Succeeded
Querying remote for config...Succeeded
Using cache server: None (https://dev.azure.com/gvfs/ci/_git/ForTests)

WARNING: Unable to validate your Scalar version
Server not configured to provide supported Scalar versions

Cloning...Succeeded
Fetching commits and trees from origin (no cache server)...Succeeded
Validating repo...Succeeded
Mounting...Succeeded

$ cd ForTests/src/
$ ls
AuthoringTests.md  GvFlt_EULA.md  GVFS.sln  License.md  nuget.config  Protocol.md  Readme.md  Settings.StyleCop

$ echo GVFS/GVFS.Common >>../folders.txt
$ echo GVFS/GVFS.UnitTests >>../folders.txt
$ echo GitHooksLoader >>../folders.txt
$ git sparse-checkout add <../folders.txt

$ ls
AuthoringTests.md  GitHooksLoader/  GvFlt_EULA.md  GVFS/  GVFS.sln  License.md  nuget.config  Protocol.md  Readme.md  Settings.StyleCop

$ echo GVFS/GVFS >>../folders2.txt
$ echo GVFS/GVFS.FunctionalTests >>../folders2.txt
$ git sparse-checkout add <../folders2.txt

$ ls
AuthoringTests.md  GitHooksLoader/  GvFlt_EULA.md  GVFS/  GVFS.sln  License.md  nuget.config  Protocol.md  Readme.md  Settings.StyleCop

$ ls GVFS
GVFS/  GVFS.Common/  GVFS.FunctionalTests/  GVFS.UnitTests/  LibGit2Sharp.NativeBinaries.props  ProjectedFSLib.NativeBinaries.props

$ git sparse-checkout list
/
/GVFS/
/GVFS/GVFS/*
/GVFS/GVFS.Common/*
/GVFS/GVFS.FunctionalTests/*
/GVFS/GVFS.UnitTests/*
/GitHooksLoader/*

```

I spun up a few remaining issues for follow-up work: #76, #77, #78.
  • Loading branch information
derrickstolee authored Aug 22, 2019
2 parents 7640bc1 + 8631c3c commit 19d745f
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 30 deletions.
2 changes: 1 addition & 1 deletion Scalar.Build/Scalar.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<PropertyGroup Label="Parameters">
<ScalarVersion>0.2.173.2</ScalarVersion>
<GitPackageVersion>2.20190820.1</GitPackageVersion>
<GitPackageVersion>2.20190822.3-sc</GitPackageVersion>
</PropertyGroup>

<PropertyGroup Label="DefaultSettings">
Expand Down
5 changes: 5 additions & 0 deletions Scalar.Common/Git/GitProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public static Result Init(Enlistment enlistment)
return new GitProcess(enlistment).InvokeGitOutsideEnlistment("init \"" + enlistment.WorkingDirectoryBackingRoot + "\"");
}

public static Result SparseCheckoutInit(Enlistment enlistment)
{
return new GitProcess(enlistment).InvokeGitInWorkingDirectoryRoot("sparse-checkout init --cone", useReadObjectHook: false);
}

public static ConfigResult GetFromGlobalConfig(string gitBinPath, string settingName)
{
return new ConfigResult(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,34 +45,14 @@ public void PrefetchByFileExtension()
}

[TestCase, Order(4)]
public void PrefetchByFileExtensionWithHydrate()
{
int expectedCount = 3;
string output = this.Enlistment.Prefetch("--files *.md --hydrate");
this.ExpectBlobCount(output, expectedCount);
output.ShouldContain("Hydrated files: " + expectedCount);
}

[TestCase, Order(5)]
public void PrefetchByFilesWithHydrateWhoseObjectsAreAlreadyDownloaded()
{
int expectedCount = 2;
string output = this.Enlistment.Prefetch(
$"--files {Path.Combine("GVFS", "GVFS", "Program.cs")};{Path.Combine("GVFS", "GVFS.FunctionalTests", "GVFS.FunctionalTests.csproj")} --hydrate");
this.ExpectBlobCount(output, expectedCount);
output.ShouldContain("Hydrated files: " + expectedCount);
output.ShouldContain("Downloaded: 0");
}

[TestCase, Order(6)]
public void PrefetchFolders()
{
this.ExpectBlobCount(this.Enlistment.Prefetch($"--folders {Path.Combine("GVFS", "GVFS")}"), 24);
this.ExpectBlobCount(this.Enlistment.Prefetch($"--folders {Path.Combine("GVFS", "GVFS", "CommandLine")}"), 23);
this.ExpectBlobCount(this.Enlistment.Prefetch($"--folders {Path.Combine("GVFS", "GVFS")};{Path.Combine("GVFS", "GVFS.FunctionalTests")}"), 72);
}

[TestCase, Order(7)]
[TestCase, Order(5)]
public void PrefetchNonExistentFilesAndFolders()
{
this.ExpectBlobCount(this.Enlistment.Prefetch("--files nonexistent.txt"), 0);
Expand Down Expand Up @@ -100,14 +80,14 @@ public void PrefetchFolderListFromFile()
File.Delete(tempFilePath);
}

[TestCase, Order(9)]
[TestCase, Order(6)]
public void PrefetchAll()
{
this.ExpectBlobCount(this.Enlistment.Prefetch("--files *"), 494);
this.ExpectBlobCount(this.Enlistment.Prefetch($"--folders {Path.DirectorySeparatorChar}"), 494);
}

[TestCase, Order(10)]
[TestCase, Order(7)]
public void NoopPrefetch()
{
this.ExpectBlobCount(this.Enlistment.Prefetch("--files *"), 494);
Expand All @@ -116,7 +96,7 @@ public void NoopPrefetch()
}

// TODO(#1219): Handle that lock files are not deleted on Mac, they are simply unlocked
[TestCase, Order(11)]
[TestCase, Order(8)]
[Category(Categories.MacTODO.TestNeedsToLockFile)]
public void PrefetchCleansUpStalePrefetchLock()
{
Expand All @@ -139,7 +119,7 @@ public void PrefetchCleansUpStalePrefetchLock()
prefetchCommitsLockFile.ShouldNotExistOnDisk(this.fileSystem);
}

[TestCase, Order(12)]
[TestCase, Order(9)]
public void PrefetchFilesFromFileListFile()
{
string tempFilePath = Path.Combine(Path.GetTempPath(), "temp.file");
Expand All @@ -161,7 +141,7 @@ public void PrefetchFilesFromFileListFile()
}
}

[TestCase, Order(13)]
[TestCase, Order(10)]
public void PrefetchFilesFromFileListStdIn()
{
string input = string.Join(
Expand All @@ -175,7 +155,7 @@ public void PrefetchFilesFromFileListStdIn()
this.ExpectBlobCount(this.Enlistment.Prefetch("--stdin-files-list", standardInput: input), 2);
}

[TestCase, Order(14)]
[TestCase, Order(11)]
public void PrefetchFolderListFromStdin()
{
string input = string.Join(
Expand Down
3 changes: 2 additions & 1 deletion Scalar.FunctionalTests/Tools/ScalarProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ public ScalarProcess(string pathToScalar, string enlistmentRoot, string localCac

public void Clone(string repositorySource, string branchToCheckout, bool skipPrefetch)
{
// TODO: consider sparse clone for functional tests
string args = string.Format(
"clone \"{0}\" \"{1}\" --branch \"{2}\" --local-cache-path \"{3}\" {4}",
"clone \"{0}\" \"{1}\" --full-clone --branch \"{2}\" --local-cache-path \"{3}\" {4}",
repositorySource,
this.enlistmentRoot,
branchToCheckout,
Expand Down
22 changes: 21 additions & 1 deletion Scalar/CommandLine/CloneVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ public class CloneVerb : ScalarVerb
HelpText = "Use this option to override the path for the local Scalar cache.")]
public string LocalCacheRoot { get; set; }

[Option(
"full-clone",
Required = false,
Default = false,
HelpText = "When cloning, create full working directory.")]
public bool FullClone { get; set; }

protected override string VerbName
{
get { return CloneVerbName; }
Expand Down Expand Up @@ -130,6 +137,7 @@ public override void Execute()
{ "Branch", this.Branch },
{ "LocalCacheRoot", this.LocalCacheRoot },
{ "SingleBranch", this.SingleBranch },
{ "FullClone", this.FullClone },
{ "NoPrefetch", this.NoPrefetch },
{ "Unattended", this.Unattended },
{ "IsElevated", ScalarPlatform.Instance.IsElevated() },
Expand Down Expand Up @@ -164,6 +172,7 @@ public override void Execute()
this.Output.WriteLine(" Cache Server: " + cacheServer);
this.Output.WriteLine(" Local Cache: " + resolvedLocalCacheRoot);
this.Output.WriteLine(" Destination: " + enlistment.EnlistmentRoot);
this.Output.WriteLine(" FullClone: " + this.FullClone);

string authErrorMessage;
if (!this.TryAuthenticate(tracer, enlistment, out authErrorMessage))
Expand Down Expand Up @@ -520,7 +529,7 @@ private Result CreateClone(
return new Result(installHooksError);
}

// Place block below in an if statement when sparse clone is available.
if (this.FullClone)
{
BlobPrefetcher prefetcher = new BlobPrefetcher(
tracer,
Expand Down Expand Up @@ -639,6 +648,17 @@ private Result TryInitRepo(ITracer tracer, GitRefs refs, Enlistment enlistmentTo
Path.Combine(repoPath, ScalarConstants.DotGit.PackedRefs),
refs.ToPackedRefs());

if (!this.FullClone)
{
GitProcess.Result sparseCheckoutResult = GitProcess.SparseCheckoutInit(enlistmentToInit);
if (sparseCheckoutResult.ExitCodeIsFailure)
{
string error = string.Format("Could not init sparse-checkout at to {0}: {1}", repoPath, sparseCheckoutResult.Errors);
tracer.RelatedError(error);
return new Result(error);
}
}

return new Result(true);
}

Expand Down

0 comments on commit 19d745f

Please sign in to comment.