Add maintenance verb and remove dehydrate verb

Add a maintenance verb that can be used to run
the LooseObjects, PackFileMainteance, and PostFetch
maintenance tasks.  For now these tasks are only called
by the functional tests, but eventually they will be
called by Scalar.Service as well.

The dehydrate verb was only around to facilated the
functional tests.  It is not removed in favor of the
maintenance verb.
This commit is contained in:
William Baker 2019-10-07 12:43:42 -07:00
Родитель 8a8ac23184
Коммит c9e1e15ebb
16 изменённых файлов: 329 добавлений и 752 удалений

Просмотреть файл

@ -6,20 +6,14 @@ namespace Scalar.Common
{
public InternalVerbParameters(
string serviceName = null,
bool startedByService = true,
string maintenanceJob = null,
string packfileMaintenanceBatchSize = null)
bool startedByService = true)
{
this.ServiceName = serviceName;
this.StartedByService = startedByService;
this.MaintenanceJob = maintenanceJob;
this.PackfileMaintenanceBatchSize = packfileMaintenanceBatchSize;
}
public string ServiceName { get; private set; }
public bool StartedByService { get; private set; }
public string MaintenanceJob { get; private set; }
public string PackfileMaintenanceBatchSize { get; private set; }
public static InternalVerbParameters FromJson(string json)
{

Просмотреть файл

@ -4,9 +4,7 @@ namespace Scalar.Common
{
Success = 0,
ParsingError = 1,
RebootRequired = 2,
UnsupportedOption = 2,
GenericError = 3,
FilterError = 4,
NullRequestData = 5
}
}

Просмотреть файл

@ -84,7 +84,7 @@ namespace Scalar.Common
public const string UpgradePrefix = "productupgrade";
public const string Clone = "clone";
public const string Dehydrate = "dehydrate";
public const string Maintenance = "maintenance";
public const string MountVerb = MountPrefix + "_verb";
public const string MountProcess = MountPrefix + "_process";
public const string MountUpgrade = MountPrefix + "_repoupgrade";

Просмотреть файл

@ -24,9 +24,6 @@ namespace Scalar.FunctionalTests
// Tests that require Scalar Service
public const string NeedsServiceVerb = "NeedsServiceVerb";
// Requires both functional and test fixes
public const string NeedsDehydrate = "NeedsDehydrate";
// Tests requires code updates so that we lock the file instead of looking for a .lock file
public const string TestNeedsToLockFile = "TestNeedsToLockFile";
}

Просмотреть файл

@ -85,7 +85,6 @@ namespace Scalar.FunctionalTests
{
excludeCategories.Add(Categories.MacTODO.NeedsNewFolderCreateNotification);
excludeCategories.Add(Categories.MacTODO.NeedsScalarConfig);
excludeCategories.Add(Categories.MacTODO.NeedsDehydrate);
excludeCategories.Add(Categories.MacTODO.NeedsServiceVerb);
excludeCategories.Add(Categories.MacTODO.TestNeedsToLockFile);
excludeCategories.Add(Categories.WindowsOnly);

Просмотреть файл

@ -194,11 +194,6 @@ namespace Scalar.FunctionalTests.Tools
return this.scalarProcess.PackfileMaintenanceStep(batchSize);
}
public string PostFetchStep()
{
return this.scalarProcess.PostFetchStep();
}
public string Status(string trace = null)
{
return this.scalarProcess.Status(trace);

Просмотреть файл

@ -123,12 +123,10 @@ namespace Scalar.FunctionalTests.Tools
}
}
public static string GetInternalParameter(string maintenanceJob = "null", string packfileMaintenanceBatchSize = "null")
public static string GetInternalParameter()
{
return $"\"{{\\\"ServiceName\\\":\\\"{ScalarServiceProcess.TestServiceName}\\\"," +
"\\\"StartedByService\\\":false," +
$"\\\"MaintenanceJob\\\":{maintenanceJob}," +
$"\\\"PackfileMaintenanceBatchSize\\\":{packfileMaintenanceBatchSize}}}\"";
"\\\"StartedByService\\\":false}\"";
}
private static T RunSqliteCommand<T>(string sqliteDbPath, Func<SqliteCommand, T> runCommand)

Просмотреть файл

@ -72,28 +72,16 @@ namespace Scalar.FunctionalTests.Tools
public string LooseObjectStep()
{
return this.CallScalar(
"dehydrate \"" + this.enlistmentRoot + "\"",
expectedExitCode: SuccessExitCode,
internalParameter: ScalarHelpers.GetInternalParameter("\\\"LooseObjects\\\""));
$"maintenance \"{this.enlistmentRoot}\" --task LooseObjects",
expectedExitCode: SuccessExitCode);
}
public string PackfileMaintenanceStep(long? batchSize)
{
string sizeString = batchSize.HasValue ? $"\\\"{batchSize.Value}\\\"" : "null";
string internalParameter = ScalarHelpers.GetInternalParameter("\\\"PackfileMaintenance\\\"", sizeString);
string sizeString = batchSize.HasValue ? $"--batch-size {batchSize.Value}" : string.Empty;
return this.CallScalar(
"dehydrate \"" + this.enlistmentRoot + "\"",
expectedExitCode: SuccessExitCode,
internalParameter: internalParameter);
}
public string PostFetchStep()
{
string internalParameter = ScalarHelpers.GetInternalParameter("\\\"PostFetch\\\"");
return this.CallScalar(
"dehydrate \"" + this.enlistmentRoot + "\"",
expectedExitCode: SuccessExitCode,
internalParameter: internalParameter);
$"maintenance \"{this.enlistmentRoot}\" --task PackfileMaintenance {sizeString}",
expectedExitCode: SuccessExitCode);
}
public string Diagnose()

Просмотреть файл

@ -328,8 +328,7 @@ namespace Scalar.CommandLine
catch (IOException ex)
{
this.Output.WriteLine("Failed: Check clone logs for details.");
EventMetadata metadata = new EventMetadata();
metadata.Add("Exception", ex.ToString());
EventMetadata metadata = this.CreateEventMetadata(ex);
this.tracer.RelatedError(metadata, $"Failed to configure Watchman integration: {ex.Message}");
}
}
@ -388,7 +387,7 @@ namespace Scalar.CommandLine
{
this.Branch = this.refs.GetDefaultBranch();
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
metadata.Add("Branch", this.Branch);
this.tracer.RelatedEvent(EventLevel.Informational, "CloneDefaultRemoteBranch", metadata);
}
@ -396,7 +395,7 @@ namespace Scalar.CommandLine
{
if (!this.refs.HasBranch(this.Branch))
{
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
metadata.Add("Branch", this.Branch);
this.tracer.RelatedEvent(EventLevel.Warning, "CloneBranchDoesNotExist", metadata);
@ -497,7 +496,7 @@ namespace Scalar.CommandLine
return false;
}
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
metadata.Add("localCacheRoot", localCacheRoot);
metadata.Add("localCacheKey", localCacheKey);
metadata.Add(TracingConstants.MessageKey.InfoMessage, "Initializing cache paths");
@ -629,7 +628,7 @@ namespace Scalar.CommandLine
GitProcess.Result result = this.git.ForceCheckout(this.Branch);
if (result.ExitCodeIsFailure)
{
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
metadata["git-output"] = result.Output;
metadata["git-errors"] = result.Errors;
this.tracer.RelatedError(metadata, "Failed to checkout repo");

Просмотреть файл

@ -1,498 +0,0 @@
using CommandLine;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Git;
using Scalar.Common.Http;
using Scalar.Common.Maintenance;
using Scalar.Common.NamedPipes;
using Scalar.Common.Tracing;
using Scalar.DiskLayoutUpgrades;
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace Scalar.CommandLine
{
[Verb(DehydrateVerb.DehydrateVerbName, HelpText = "EXPERIMENTAL FEATURE - Fully dehydrate a Scalar repo")]
public class DehydrateVerb : ScalarVerb.ForExistingEnlistment
{
private const string DehydrateVerbName = "dehydrate";
[Option(
"confirm",
Default = false,
Required = false,
HelpText = "Pass in this flag to actually do the dehydrate")]
public bool Confirmed { get; set; }
[Option(
"no-status",
Default = false,
Required = false,
HelpText = "Skip 'git status' before dehydrating")]
public bool NoStatus { get; set; }
protected override string VerbName
{
get { return DehydrateVerb.DehydrateVerbName; }
}
protected override void Execute(ScalarEnlistment enlistment)
{
using (JsonTracer tracer = new JsonTracer(ScalarConstants.ScalarEtwProviderName, "Dehydrate"))
{
tracer.AddLogFileEventListener(
ScalarEnlistment.GetNewScalarLogFileName(enlistment.ScalarLogsRoot, ScalarConstants.LogFileTypes.Dehydrate),
EventLevel.Informational,
Keywords.Any);
tracer.WriteStartEvent(
enlistment.EnlistmentRoot,
enlistment.RepoUrl,
CacheServerResolver.GetUrlFromConfig(enlistment),
new EventMetadata
{
{ "Confirmed", this.Confirmed },
{ "NoStatus", this.NoStatus },
{ "NamedPipeName", enlistment.NamedPipeName },
{ nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
});
// This is only intended to be run by functional tests
if (this.MaintenanceJob != null)
{
this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig: null, serverScalarConfig: null, cacheServer: null);
PhysicalFileSystem fileSystem = new PhysicalFileSystem();
using (ScalarContext context = new ScalarContext(tracer, fileSystem, enlistment))
{
switch (this.MaintenanceJob)
{
case "LooseObjects":
(new LooseObjectsStep(context, forceRun: true)).Execute();
return;
case "PackfileMaintenance":
(new PackfileMaintenanceStep(
context,
forceRun: true,
batchSize: this.PackfileMaintenanceBatchSize ?? PackfileMaintenanceStep.DefaultBatchSize)).Execute();
return;
case "PostFetch":
(new PostFetchStep(context, new System.Collections.Generic.List<string>(), requireObjectCacheLock: false)).Execute();
return;
default:
this.ReportErrorAndExit($"Unknown maintenance job requested: {this.MaintenanceJob}");
break;
}
}
}
if (!this.Confirmed)
{
this.Output.WriteLine(
@"WARNING: THIS IS AN EXPERIMENTAL FEATURE
Dehydrate will back up your src folder, and then create a new, empty src folder
with a fresh virtualization of the repo. All of your downloaded objects, branches,
and siblings of the src folder will be preserved. Your modified working directory
files will be moved to the backup, and your new working directory will not have
any of your uncommitted changes.
Before you dehydrate, make sure you have committed any working directory changes
you want to keep. If you choose not to, you can still find your uncommitted changes
in the backup folder, but it will be harder to find them because 'git status'
will not work in the backup.
To actually execute the dehydrate, run 'scalar dehydrate --confirm' from the parent
of your enlistment's src folder.
");
return;
}
this.CheckGitStatus(tracer, enlistment);
string backupRoot = Path.GetFullPath(Path.Combine(enlistment.EnlistmentRoot, "dehydrate_backup", DateTime.Now.ToString("yyyyMMdd_HHmmss")));
this.Output.WriteLine();
this.WriteMessage(tracer, "Starting dehydration. All of your existing files will be backed up in " + backupRoot);
this.WriteMessage(tracer, "WARNING: If you abort the dehydrate after this point, the repo may become corrupt");
this.Output.WriteLine();
this.Unmount(tracer);
string error;
if (!DiskLayoutUpgrade.TryCheckDiskLayoutVersion(tracer, enlistment.EnlistmentRoot, out error))
{
this.ReportErrorAndExit(tracer, error);
}
RetryConfig retryConfig;
if (!RetryConfig.TryLoadFromGitConfig(tracer, enlistment, out retryConfig, out error))
{
this.ReportErrorAndExit(tracer, "Failed to determine Scalar timeout and max retries: " + error);
}
string errorMessage;
if (!this.TryAuthenticate(tracer, enlistment, out errorMessage))
{
this.ReportErrorAndExit(tracer, errorMessage);
}
// Local cache and objects paths are required for TryDownloadGitObjects
this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig, serverScalarConfig: null, cacheServer: null);
if (this.TryBackupFiles(tracer, enlistment, backupRoot))
{
if (this.TryDownloadGitObjects(tracer, enlistment, retryConfig) &&
this.TryRecreateIndex(tracer, enlistment))
{
this.Mount(tracer);
this.Output.WriteLine();
this.WriteMessage(tracer, "The repo was successfully dehydrated and remounted");
}
}
else
{
this.Output.WriteLine();
this.WriteMessage(tracer, "ERROR: Backup failed. We will attempt to mount, but you may need to reclone if that fails");
this.Mount(tracer);
this.WriteMessage(tracer, "Dehydrate failed, but remounting succeeded");
}
}
}
private void CheckGitStatus(ITracer tracer, ScalarEnlistment enlistment)
{
if (!this.NoStatus)
{
this.WriteMessage(tracer, "Running git status before dehydrating to make sure you don't have any pending changes.");
this.WriteMessage(tracer, "If this takes too long, you can abort and run dehydrate with --no-status to skip this safety check.");
this.Output.WriteLine();
bool isMounted = false;
GitProcess.Result statusResult = null;
if (!this.ShowStatusWhileRunning(
() =>
{
if (this.ExecuteScalarVerb<StatusVerb>(tracer) != ReturnCode.Success)
{
return false;
}
isMounted = true;
GitProcess git = new GitProcess(enlistment);
statusResult = git.Status(allowObjectDownloads: false, useStatusCache: false, showUntracked: true);
if (statusResult.ExitCodeIsFailure)
{
return false;
}
if (!statusResult.Output.Contains("nothing to commit, working tree clean"))
{
return false;
}
return true;
},
"Running git status",
suppressGvfsLogMessage: true))
{
this.Output.WriteLine();
if (!isMounted)
{
this.WriteMessage(tracer, "Failed to run git status because the repo is not mounted");
this.WriteMessage(tracer, "Either mount first, or run with --no-status");
}
else if (statusResult.ExitCodeIsFailure)
{
this.WriteMessage(tracer, "Failed to run git status: " + statusResult.Errors);
}
else
{
this.WriteMessage(tracer, statusResult.Output);
this.WriteMessage(tracer, "git status reported that you have dirty files");
this.WriteMessage(tracer, "Either commit your changes or run dehydrate with --no-status");
}
this.ReportErrorAndExit(tracer, "Dehydrate was aborted");
}
}
}
private void Unmount(ITracer tracer)
{
if (!this.ShowStatusWhileRunning(
() =>
{
return
this.ExecuteScalarVerb<StatusVerb>(tracer) != ReturnCode.Success ||
this.ExecuteScalarVerb<UnmountVerb>(tracer) == ReturnCode.Success;
},
"Unmounting",
suppressGvfsLogMessage: true))
{
this.ReportErrorAndExit(tracer, "Unable to unmount.");
}
}
private void Mount(ITracer tracer)
{
if (!this.ShowStatusWhileRunning(
() =>
{
return this.ExecuteScalarVerb<MountVerb>(tracer) == ReturnCode.Success;
},
"Mounting"))
{
this.ReportErrorAndExit(tracer, "Failed to mount after dehydrating.");
}
}
private bool TryBackupFiles(ITracer tracer, ScalarEnlistment enlistment, string backupRoot)
{
string backupSrc = Path.Combine(backupRoot, "src");
string backupGit = Path.Combine(backupRoot, ".git");
string backupGvfs = Path.Combine(backupRoot, ScalarPlatform.Instance.Constants.DotScalarRoot);
string backupDatabases = Path.Combine(backupGvfs, ScalarConstants.DotScalar.Databases.Name);
string errorMessage = string.Empty;
if (!this.ShowStatusWhileRunning(
() =>
{
string ioError;
if (!this.TryIO(tracer, () => Directory.CreateDirectory(backupRoot), "Create backup directory", out ioError) ||
!this.TryIO(tracer, () => Directory.CreateDirectory(backupGit), "Create backup .git directory", out ioError) ||
!this.TryIO(tracer, () => Directory.CreateDirectory(backupGvfs), "Create backup .scalar directory", out ioError) ||
!this.TryIO(tracer, () => Directory.CreateDirectory(backupDatabases), "Create backup .scalar databases directory", out ioError))
{
errorMessage = "Failed to create backup folders at " + backupRoot + ": " + ioError;
return false;
}
// Move the current src folder to the backup location...
if (!this.TryIO(tracer, () => Directory.Move(enlistment.WorkingDirectoryRoot, backupSrc), "Move the src folder", out ioError))
{
errorMessage = "Failed to move the src folder: " + ioError + Environment.NewLine;
errorMessage += "Make sure you have no open handles or running processes in the src folder";
return false;
}
// ... but move the .git folder back to the new src folder so we can preserve objects, refs, logs...
if (!this.TryIO(tracer, () => Directory.CreateDirectory(enlistment.WorkingDirectoryRoot), "Create new src folder", out errorMessage) ||
!this.TryIO(tracer, () => Directory.Move(Path.Combine(backupSrc, ".git"), enlistment.DotGitRoot), "Keep existing .git folder", out errorMessage))
{
return false;
}
// ... backup the .scalar hydration-related data structures...
string databasesFolder = Path.Combine(enlistment.DotScalarRoot, ScalarConstants.DotScalar.Databases.Name);
if (!this.TryBackupFilesInFolder(tracer, databasesFolder, backupDatabases, searchPattern: "*", filenamesToSkip: "RepoMetadata.dat"))
{
return false;
}
// ... backup everything related to the .git\index...
if (!this.TryIO(
tracer,
() => File.Move(
Path.Combine(enlistment.DotGitRoot, ScalarConstants.DotGit.IndexName),
Path.Combine(backupGit, ScalarConstants.DotGit.IndexName)),
"Backup the git index",
out errorMessage))
{
return false;
}
// ... backup all .git\*.lock files
if (!this.TryBackupFilesInFolder(tracer, enlistment.DotGitRoot, backupGit, searchPattern: "*.lock"))
{
return false;
}
return true;
},
"Backing up your files"))
{
this.Output.WriteLine();
this.WriteMessage(tracer, "ERROR: " + errorMessage);
return false;
}
return true;
}
private bool TryBackupFilesInFolder(ITracer tracer, string folderPath, string backupPath, string searchPattern, params string[] filenamesToSkip)
{
string errorMessage;
foreach (string file in Directory.GetFiles(folderPath, searchPattern))
{
string fileName = Path.GetFileName(file);
if (!filenamesToSkip.Any(x => x.Equals(fileName, StringComparison.OrdinalIgnoreCase)))
{
if (!this.TryIO(
tracer,
() => File.Move(file, file.Replace(folderPath, backupPath)),
$"Backing up {Path.GetFileName(file)}",
out errorMessage))
{
return false;
}
}
}
return true;
}
private bool TryDownloadGitObjects(ITracer tracer, ScalarEnlistment enlistment, RetryConfig retryConfig)
{
string errorMessage = null;
if (!this.ShowStatusWhileRunning(
() =>
{
CacheServerInfo cacheServer = new CacheServerInfo(enlistment.RepoUrl, null);
using (GitObjectsHttpRequestor objectRequestor = new GitObjectsHttpRequestor(tracer, enlistment, cacheServer, retryConfig))
{
PhysicalFileSystem fileSystem = new PhysicalFileSystem();
ScalarGitObjects gitObjects = new ScalarGitObjects(new ScalarContext(tracer, fileSystem, enlistment), objectRequestor);
GitProcess.Result revParseResult = enlistment.CreateGitProcess().RevParse("HEAD");
if (revParseResult.ExitCodeIsFailure)
{
errorMessage = "Unable to determine HEAD commit id: " + revParseResult.Errors;
return false;
}
string headCommit = revParseResult.Output.TrimEnd('\n');
if (!this.TryDownloadCommit(headCommit, objectRequestor, gitObjects, out errorMessage) ||
!this.TryDownloadRootGitAttributes(enlistment, gitObjects, out errorMessage))
{
return false;
}
}
return true;
},
"Downloading git objects",
suppressGvfsLogMessage: true))
{
this.WriteMessage(tracer, errorMessage);
return false;
}
return true;
}
private bool TryRecreateIndex(ITracer tracer, ScalarEnlistment enlistment)
{
string errorMessage = null;
if (!this.ShowStatusWhileRunning(
() =>
{
// Create a new index based on the new minimal modified paths
GitProcess git = new GitProcess(enlistment);
GitProcess.Result checkoutResult = git.ForceCheckout("HEAD");
errorMessage = checkoutResult.Errors;
return checkoutResult.ExitCodeIsSuccess;
},
"Recreating git index",
suppressGvfsLogMessage: true))
{
this.WriteMessage(tracer, "Failed to recreate index: " + errorMessage);
return false;
}
return true;
}
private void WriteMessage(ITracer tracer, string message)
{
this.Output.WriteLine(message);
tracer.RelatedEvent(
EventLevel.Informational,
"Dehydrate",
new EventMetadata
{
{ TracingConstants.MessageKey.InfoMessage, message }
});
}
private ReturnCode ExecuteScalarVerb<TVerb>(ITracer tracer)
where TVerb : ScalarVerb, new()
{
try
{
ReturnCode returnCode;
StringBuilder commandOutput = new StringBuilder();
using (StringWriter writer = new StringWriter(commandOutput))
{
returnCode = this.Execute<TVerb>(this.EnlistmentRootPathParameter, verb => verb.Output = writer);
}
tracer.RelatedEvent(
EventLevel.Informational,
typeof(TVerb).Name,
new EventMetadata
{
{ "Output", commandOutput.ToString() },
{ "ReturnCode", returnCode }
});
return returnCode;
}
catch (Exception e)
{
tracer.RelatedError(
new EventMetadata
{
{ "Verb", typeof(TVerb).Name },
{ "Exception", e.ToString() }
},
"ExecuteScalarVerb: Caught exception");
return ReturnCode.GenericError;
}
}
private bool TryIO(ITracer tracer, Action action, string description, out string error)
{
try
{
action();
tracer.RelatedEvent(
EventLevel.Informational,
"TryIO",
new EventMetadata
{
{ "Description", description }
});
error = null;
return true;
}
catch (Exception e)
{
error = e.Message;
tracer.RelatedError(
new EventMetadata
{
{ "Description", description },
{ "Error", error }
},
"TryIO: Caught exception performing action");
}
return false;
}
}
}

Просмотреть файл

@ -58,7 +58,6 @@ namespace Scalar.CommandLine
// By using MountPrefix ("mount") DisplayMostRecent will display either mount_verb, mount_upgrade, or mount_process, whichever is more recent
this.DisplayMostRecent(scalarLogsRoot, ScalarConstants.LogFileTypes.MountPrefix);
this.DisplayMostRecent(scalarLogsRoot, ScalarConstants.LogFileTypes.Prefetch);
this.DisplayMostRecent(scalarLogsRoot, ScalarConstants.LogFileTypes.Dehydrate);
this.DisplayMostRecent(scalarLogsRoot, ScalarConstants.LogFileTypes.Repair);
this.DisplayMostRecent(scalarLogsRoot, ScalarConstants.LogFileTypes.Sparse);
@ -121,7 +120,6 @@ namespace Scalar.CommandLine
ScalarConstants.LogFileTypes.Clone,
ScalarConstants.LogFileTypes.MountPrefix,
ScalarConstants.LogFileTypes.Prefetch,
ScalarConstants.LogFileTypes.Dehydrate,
ScalarConstants.LogFileTypes.Repair,
ScalarConstants.LogFileTypes.Sparse,
ScalarConstants.LogFileTypes.Service,

Просмотреть файл

@ -0,0 +1,118 @@
using System;
using CommandLine;
using Scalar.Common;
using Scalar.Common.FileSystem;
using Scalar.Common.Http;
using Scalar.Common.Maintenance;
using Scalar.Common.Tracing;
namespace Scalar.CommandLine
{
[Verb(MaintenanceVerb.MaintenanceVerbName, HelpText = "Perform a maintenance task in a Scalar repo")]
public class MaintenanceVerb : ScalarVerb.ForExistingEnlistment
{
private const string MaintenanceVerbName = "maintenance";
private const string LooseObjectsTaskName = "LooseObjects";
private const string PackfileMaintenanceTaskName = "PackfileMaintenance";
private const string PostFetchTaskName = "PostFetch";
private const string BatchSizeOptionName = "batch-size";
[Option(
't',
"task",
Required = true,
Default = "",
HelpText = "Maintenance task to run. Allowed values are '"
+ LooseObjectsTaskName + "', '"
+ PackfileMaintenanceTaskName + "', '"
+ PostFetchTaskName + "'")]
public string MaintenanceTask { get; set; }
[Option(
BatchSizeOptionName,
Required = false,
Default = "",
HelpText = "Batch size. This option can only be used with the '" + PackfileMaintenanceTaskName + "' task")]
public string PackfileMaintenanceBatchSize { get; set; }
protected override string VerbName
{
get { return MaintenanceVerb.MaintenanceVerbName; }
}
protected override void Execute(ScalarEnlistment enlistment)
{
using (JsonTracer tracer = new JsonTracer(ScalarConstants.ScalarEtwProviderName, MaintenanceVerbName))
{
tracer.AddLogFileEventListener(
ScalarEnlistment.GetNewScalarLogFileName(enlistment.ScalarLogsRoot, ScalarConstants.LogFileTypes.Maintenance),
EventLevel.Informational,
Keywords.Any);
tracer.WriteStartEvent(
enlistment.EnlistmentRoot,
enlistment.RepoUrl,
CacheServerResolver.GetUrlFromConfig(enlistment),
new EventMetadata
{
{ nameof(this.MaintenanceTask), this.MaintenanceTask },
{ nameof(this.PackfileMaintenanceBatchSize), this.PackfileMaintenanceBatchSize },
{ nameof(this.EnlistmentRootPathParameter), this.EnlistmentRootPathParameter },
});
this.InitializeLocalCacheAndObjectsPaths(tracer, enlistment, retryConfig: null, serverScalarConfig: null, cacheServer: null);
PhysicalFileSystem fileSystem = new PhysicalFileSystem();
using (ScalarContext context = new ScalarContext(tracer, fileSystem, enlistment))
{
try
{
switch (this.MaintenanceTask)
{
case LooseObjectsTaskName:
this.FailIfBatchSizeSet(tracer);
(new LooseObjectsStep(context, forceRun: true)).Execute();
return;
case PackfileMaintenanceTaskName:
(new PackfileMaintenanceStep(
context,
forceRun: true,
batchSize: string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize) ?
PackfileMaintenanceStep.DefaultBatchSize :
this.PackfileMaintenanceBatchSize)).Execute();
return;
case PostFetchTaskName:
this.FailIfBatchSizeSet(tracer);
(new PostFetchStep(context, new System.Collections.Generic.List<string>(), requireObjectCacheLock: false)).Execute();
return;
default:
this.ReportErrorAndExit($"Unknown maintenance task requested: '{this.MaintenanceTask}'");
break;
}
}
catch (Exception e) when (!(e is VerbAbortedException))
{
string error = $"Exception thrown while running {this.MaintenanceTask} task: {e.Message}";
EventMetadata metadata = this.CreateEventMetadata(e);
tracer.RelatedError(metadata, error);
this.ReportErrorAndExit(tracer, ReturnCode.GenericError, error);
}
}
}
}
private void FailIfBatchSizeSet(ITracer tracer)
{
if (!string.IsNullOrWhiteSpace(this.PackfileMaintenanceBatchSize))
{
this.ReportErrorAndExit(
tracer,
ReturnCode.UnsupportedOption,
$"--{BatchSizeOptionName} can only be used with the {PackfileMaintenanceTaskName} task");
}
}
}
}

Просмотреть файл

@ -52,7 +52,7 @@ namespace Scalar.CommandLine
try
{
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
tracer.RelatedEvent(EventLevel.Informational, "PerformPrefetch", metadata);
GitObjectsHttpRequestor objectRequestor;
@ -77,11 +77,7 @@ namespace Scalar.CommandLine
foreach (Exception innerException in aggregateException.Flatten().InnerExceptions)
{
tracer.RelatedError(
new EventMetadata
{
{ "Verb", typeof(PrefetchVerb).Name },
{ "Exception", innerException.ToString() }
},
this.CreateEventMetadata(innerException),
$"Unhandled {innerException.GetType().Name}: {innerException.Message}");
}
@ -93,11 +89,7 @@ namespace Scalar.CommandLine
"Cannot prefetch {0}. " + ConsoleHelper.GetScalarLogMessage(enlistment.EnlistmentRoot),
enlistment.EnlistmentRoot);
tracer.RelatedError(
new EventMetadata
{
{ "Verb", typeof(PrefetchVerb).Name },
{ "Exception", e.ToString() }
},
this.CreateEventMetadata(e),
$"Unhandled {e.GetType().Name}: {e.Message}");
Environment.ExitCode = (int)ReturnCode.GenericError;

Просмотреть файл

@ -101,16 +101,6 @@ namespace Scalar.CommandLine
this.ServiceName = mountInternal.ServiceName;
}
if (!string.IsNullOrEmpty(mountInternal.MaintenanceJob))
{
this.MaintenanceJob = mountInternal.MaintenanceJob;
}
if (!string.IsNullOrEmpty(mountInternal.PackfileMaintenanceBatchSize))
{
this.PackfileMaintenanceBatchSize = mountInternal.PackfileMaintenanceBatchSize;
}
this.StartedByService = mountInternal.StartedByService;
}
catch (JsonReaderException e)
@ -123,10 +113,6 @@ namespace Scalar.CommandLine
public string ServiceName { get; set; }
public string MaintenanceJob { get; set; }
public string PackfileMaintenanceBatchSize { get; set; }
public bool StartedByService { get; set; }
public bool Unattended { get; private set; }
@ -326,6 +312,19 @@ namespace Scalar.CommandLine
return result;
}
protected EventMetadata CreateEventMetadata(Exception e = null)
{
EventMetadata metadata = new EventMetadata();
metadata.Add("Area", $"{this.VerbName}_Verb");
metadata.Add("Verb", this.VerbName);
if (e != null)
{
metadata.Add("Exception", e.ToString());
}
return metadata;
}
protected void ReportErrorAndExit(ITracer tracer, ReturnCode exitCode, string error, params object[] args)
{
if (!string.IsNullOrEmpty(error))
@ -598,7 +597,7 @@ You can specify a URL, a name of a configured cache server, or the special names
protected void LogEnlistmentInfoAndSetConfigValues(ITracer tracer, GitProcess git, ScalarEnlistment enlistment)
{
string mountId = CreateMountId();
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
metadata.Add(nameof(RepoMetadata.Instance.EnlistmentId), RepoMetadata.Instance.EnlistmentId);
metadata.Add(nameof(mountId), mountId);
metadata.Add("Enlistment", enlistment);
@ -739,7 +738,7 @@ You can specify a URL, a name of a configured cache server, or the special names
errorMessage += "Server not configured to provide supported Scalar versions";
}
EventMetadata metadata = new EventMetadata();
EventMetadata metadata = this.CreateEventMetadata();
tracer.RelatedError(metadata, errorMessage, Keywords.Network);
return false;

Просмотреть файл

@ -19,7 +19,7 @@ namespace Scalar
typeof(CacheServerVerb),
typeof(CloneVerb),
typeof(ConfigVerb),
typeof(DehydrateVerb),
typeof(MaintenanceVerb),
typeof(DiagnoseVerb),
typeof(LogVerb),
typeof(MountVerb),

Просмотреть файл

@ -1,183 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(SolutionDir)\Scalar.Build\Scalar.cs.props" />
<PropertyGroup>
<ProjectGuid>{32220664-594C-4425-B9A0-88E0BE2F3D2A}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Scalar</RootNamespace>
<AssemblyName>Scalar</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="CommandLine, Version=2.0.275.0, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\CommandLineParser.2.1.1-beta\lib\net45\CommandLine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Data.Sqlite, Version=2.2.4.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Sqlite.Core.2.2.4\lib\netstandard2.0\Microsoft.Data.Sqlite.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NuGet.Commands, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Commands.4.9.2\lib\net46\NuGet.Commands.dll</HintPath>
</Reference>
<Reference Include="NuGet.Common, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Common.4.9.2\lib\net46\NuGet.Common.dll</HintPath>
</Reference>
<Reference Include="NuGet.Configuration, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Configuration.4.9.2\lib\net46\NuGet.Configuration.dll</HintPath>
</Reference>
<Reference Include="NuGet.Credentials, Version=4.9.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Credentials.4.9.2\lib\net46\NuGet.Credentials.dll</HintPath>
</Reference>
<Reference Include="NuGet.DependencyResolver.Core, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.DependencyResolver.Core.4.9.2\lib\net46\NuGet.DependencyResolver.Core.dll</HintPath>
</Reference>
<Reference Include="NuGet.Frameworks, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Frameworks.4.9.2\lib\net46\NuGet.Frameworks.dll</HintPath>
</Reference>
<Reference Include="NuGet.LibraryModel, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.LibraryModel.4.9.2\lib\net46\NuGet.LibraryModel.dll</HintPath>
</Reference>
<Reference Include="NuGet.Packaging, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Packaging.4.9.2\lib\net46\NuGet.Packaging.dll</HintPath>
</Reference>
<Reference Include="NuGet.Packaging.Core, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Packaging.Core.4.9.2\lib\net46\NuGet.Packaging.Core.dll</HintPath>
</Reference>
<Reference Include="NuGet.ProjectModel, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.ProjectModel.4.9.2\lib\net46\NuGet.ProjectModel.dll</HintPath>
</Reference>
<Reference Include="NuGet.Protocol, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Protocol.4.9.2\lib\net46\NuGet.Protocol.dll</HintPath>
</Reference>
<Reference Include="NuGet.Versioning, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Versioning.4.9.2\lib\net46\NuGet.Versioning.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.1.12.351, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.12\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.1.12.351, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.12\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.1.12.351, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.12\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.1.12.351, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.12\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.IO.Compression, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Security" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommandLine\CacheServerVerb.cs" />
<Compile Include="CommandLine\CloneVerb.cs" />
<Compile Include="CommandLine\ConfigVerb.cs" />
<Compile Include="CommandLine\DehydrateVerb.cs" />
<Compile Include="CommandLine\DiagnoseVerb.cs" />
<Compile Include="CommandLine\ScalarVerb.cs" />
<Compile Include="CommandLine\LogVerb.cs" />
<Compile Include="CommandLine\MountVerb.cs" />
<Compile Include="CommandLine\PrefetchVerb.cs" />
<Compile Include="CommandLine\UpgradeVerb.cs" />
<Compile Include="RepairJobs\GitHeadRepairJob.cs" />
<Compile Include="RepairJobs\GitConfigRepairJob.cs" />
<Compile Include="RepairJobs\RepairJob.cs" />
<Compile Include="RepairJobs\RepoMetadataDatabaseRepairJob.cs" />
<Compile Include="CommandLine\RepairVerb.cs" />
<Compile Include="CommandLine\ServiceVerb.cs" />
<Compile Include="CommandLine\StatusVerb.cs" />
<Compile Include="CommandLine\UnmountVerb.cs" />
<Compile Include="Program.cs" />
<Compile Include="..\Scalar.PlatformLoader\PlatformLoader.Windows.cs">
<Link>PlatformLoader.Windows.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<Content Include="Images\scalar.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Scalar.Common\Scalar.Common.csproj">
<Project>{374bf1e5-0b2d-4d4a-bd5e-4212299def09}</Project>
<Name>Scalar.Common</Name>
</ProjectReference>
<ProjectReference Include="..\Scalar.Platform.Windows\Scalar.Platform.Windows.csproj">
<Project>{4ce404e7-d3fc-471c-993c-64615861ea63}</Project>
<Name>Scalar.Platform.Windows</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.CodeFixes.dll" />
<Analyzer Include="..\..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<Import Project="..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
<Error Condition="!Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
<Error Condition="!Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
</Target>
<Import Project="..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
<Import Project="..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(SolutionDir)\Scalar.Build\Scalar.cs.props" />
<PropertyGroup>
<ProjectGuid>{32220664-594C-4425-B9A0-88E0BE2F3D2A}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Scalar</RootNamespace>
<AssemblyName>Scalar</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="CommandLine, Version=2.0.275.0, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\CommandLineParser.2.1.1-beta\lib\net45\CommandLine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Data.Sqlite, Version=2.2.4.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.Data.Sqlite.Core.2.2.4\lib\netstandard2.0\Microsoft.Data.Sqlite.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NuGet.Commands, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Commands.4.9.2\lib\net46\NuGet.Commands.dll</HintPath>
</Reference>
<Reference Include="NuGet.Common, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Common.4.9.2\lib\net46\NuGet.Common.dll</HintPath>
</Reference>
<Reference Include="NuGet.Configuration, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Configuration.4.9.2\lib\net46\NuGet.Configuration.dll</HintPath>
</Reference>
<Reference Include="NuGet.Credentials, Version=4.9.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Credentials.4.9.2\lib\net46\NuGet.Credentials.dll</HintPath>
</Reference>
<Reference Include="NuGet.DependencyResolver.Core, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.DependencyResolver.Core.4.9.2\lib\net46\NuGet.DependencyResolver.Core.dll</HintPath>
</Reference>
<Reference Include="NuGet.Frameworks, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Frameworks.4.9.2\lib\net46\NuGet.Frameworks.dll</HintPath>
</Reference>
<Reference Include="NuGet.LibraryModel, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.LibraryModel.4.9.2\lib\net46\NuGet.LibraryModel.dll</HintPath>
</Reference>
<Reference Include="NuGet.Packaging, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Packaging.4.9.2\lib\net46\NuGet.Packaging.dll</HintPath>
</Reference>
<Reference Include="NuGet.Packaging.Core, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Packaging.Core.4.9.2\lib\net46\NuGet.Packaging.Core.dll</HintPath>
</Reference>
<Reference Include="NuGet.ProjectModel, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.ProjectModel.4.9.2\lib\net46\NuGet.ProjectModel.dll</HintPath>
</Reference>
<Reference Include="NuGet.Protocol, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Protocol.4.9.2\lib\net46\NuGet.Protocol.dll</HintPath>
</Reference>
<Reference Include="NuGet.Versioning, Version=4.9.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\NuGet.Versioning.4.9.2\lib\net46\NuGet.Versioning.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.1.12.351, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.12\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.1.12.351, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.12\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.1.12.351, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.12\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.1.12.351, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.12\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IdentityModel" />
<Reference Include="System.IO.Compression, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Security" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommandLine\CacheServerVerb.cs" />
<Compile Include="CommandLine\CloneVerb.cs" />
<Compile Include="CommandLine\ConfigVerb.cs" />
<Compile Include="CommandLine\DiagnoseVerb.cs" />
<Compile Include="CommandLine\MaintenanceVerb.cs" />
<Compile Include="CommandLine\ScalarVerb.cs" />
<Compile Include="CommandLine\LogVerb.cs" />
<Compile Include="CommandLine\MountVerb.cs" />
<Compile Include="CommandLine\PrefetchVerb.cs" />
<Compile Include="CommandLine\UpgradeVerb.cs" />
<Compile Include="RepairJobs\GitHeadRepairJob.cs" />
<Compile Include="RepairJobs\GitConfigRepairJob.cs" />
<Compile Include="RepairJobs\RepairJob.cs" />
<Compile Include="RepairJobs\RepoMetadataDatabaseRepairJob.cs" />
<Compile Include="CommandLine\RepairVerb.cs" />
<Compile Include="CommandLine\ServiceVerb.cs" />
<Compile Include="CommandLine\StatusVerb.cs" />
<Compile Include="CommandLine\UnmountVerb.cs" />
<Compile Include="Program.cs" />
<Compile Include="..\Scalar.PlatformLoader\PlatformLoader.Windows.cs">
<Link>PlatformLoader.Windows.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<Content Include="Images\scalar.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Scalar.Common\Scalar.Common.csproj">
<Project>{374bf1e5-0b2d-4d4a-bd5e-4212299def09}</Project>
<Name>Scalar.Common</Name>
</ProjectReference>
<ProjectReference Include="..\Scalar.Platform.Windows\Scalar.Platform.Windows.csproj">
<Project>{4ce404e7-d3fc-471c-993c-64615861ea63}</Project>
<Name>Scalar.Platform.Windows</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.CodeFixes.dll" />
<Analyzer Include="..\..\packages\StyleCop.Analyzers.1.0.2\analyzers\dotnet\cs\StyleCop.Analyzers.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<Import Project="..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
<Error Condition="!Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
<Error Condition="!Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
</Target>
<Import Project="..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
<Import Project="..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('..\..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.12\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
-->
</Project>