зеркало из https://github.com/microsoft/scalar.git
*.{md,cs}: remove CR line endings
Re-standardize on LF thoughout the repository, following on
from commit 6a8a91fb83
.
This commit is contained in:
Родитель
02890e3f85
Коммит
64a8fd72fe
72
SECURITY.md
72
SECURITY.md
|
@ -1,37 +1,37 @@
|
|||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
|
@ -1,4 +1,4 @@
|
|||
using Scalar.Common.Git;
|
||||
using Scalar.Common.Git;
|
||||
using Scalar.Common.Tracing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Scalar.Common.RepoRegistry
|
||||
|
|
|
@ -33,13 +33,13 @@ namespace Scalar.Tests
|
|||
return this.args.Remove(arg);
|
||||
}
|
||||
|
||||
public void AddGlobalSetupIfNeeded(string globalSetup)
|
||||
{
|
||||
// If there are any test filters, the GlobalSetup still needs to run so add it.
|
||||
if (this.args.Any(x => x.StartsWith("--test=")))
|
||||
{
|
||||
this.args.Add($"--test={globalSetup}");
|
||||
}
|
||||
public void AddGlobalSetupIfNeeded(string globalSetup)
|
||||
{
|
||||
// If there are any test filters, the GlobalSetup still needs to run so add it.
|
||||
if (this.args.Any(x => x.StartsWith("--test=")))
|
||||
{
|
||||
this.args.Add($"--test={globalSetup}");
|
||||
}
|
||||
}
|
||||
|
||||
public int RunTests(ICollection<string> includeCategories, ICollection<string> excludeCategories)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Scalar.FunctionalTests.FileSystemRunners;
|
||||
using Scalar.FunctionalTests.Tools;
|
||||
using Scalar.Tests.Should;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Scalar.FunctionalTests.FileSystemRunners;
|
||||
using Scalar.FunctionalTests.Should;
|
||||
using Scalar.FunctionalTests.Tools;
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace Scalar.FunctionalTests.Tests.EnlistmentPerFixture
|
|||
|
||||
bool timerScheduled = false;
|
||||
|
||||
// Service starts upgrade checks after 60 seconds.
|
||||
// Service starts upgrade checks after 60 seconds.
|
||||
Thread.Sleep(TimeSpan.FromSeconds(60));
|
||||
for (int trialCount = 0; trialCount < 30; trialCount++)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Scalar.Tests.Should;
|
||||
|
||||
namespace Scalar.FunctionalTests.Tests.GitRepoPerFixture
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Scalar.FunctionalTests.Tools;
|
||||
|
||||
namespace Scalar.FunctionalTests.Tests.GitRepoPerFixture
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
|
@ -2,16 +2,16 @@ using System.Xml.Serialization;
|
|||
|
||||
namespace Scalar.Service.UI.Data
|
||||
{
|
||||
[XmlRoot("action")]
|
||||
public class ActionItem
|
||||
{
|
||||
[XmlAttribute("content")]
|
||||
public string Content { get; set; }
|
||||
|
||||
[XmlAttribute("arguments")]
|
||||
public string Arguments { get; set; }
|
||||
|
||||
[XmlAttribute("activationtype")]
|
||||
public string ActivationType { get; set; }
|
||||
[XmlRoot("action")]
|
||||
public class ActionItem
|
||||
{
|
||||
[XmlAttribute("content")]
|
||||
public string Content { get; set; }
|
||||
|
||||
[XmlAttribute("arguments")]
|
||||
public string Arguments { get; set; }
|
||||
|
||||
[XmlAttribute("activationtype")]
|
||||
public string ActivationType { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public interface IToastNotifier
|
||||
{
|
||||
Action<string> UserResponseCallback { get; set; }
|
||||
void Notify(string title, string message, string actionButtonTitle, string callbackArgs);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public interface IToastNotifier
|
||||
{
|
||||
Action<string> UserResponseCallback { get; set; }
|
||||
void Notify(string title, string message, string actionButtonTitle, string callbackArgs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,42 +14,42 @@ using XmlDocument = Windows.Data.Xml.Dom.XmlDocument;
|
|||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
ScalarPlatformLoader.Initialize();
|
||||
|
||||
using (JsonTracer tracer = new JsonTracer("Microsoft.Git.GVFS.Service.UI", "Service.UI"))
|
||||
{
|
||||
string error;
|
||||
string serviceUILogDirectory = ScalarPlatform.Instance.GetLogsDirectoryForGVFSComponent(ScalarConstants.Service.UIName);
|
||||
if (!ScalarPlatform.Instance.FileSystem.TryCreateDirectoryWithAdminAndUserModifyPermissions(serviceUILogDirectory, out error))
|
||||
{
|
||||
EventMetadata metadata = new EventMetadata();
|
||||
metadata.Add(nameof(serviceUILogDirectory), serviceUILogDirectory);
|
||||
metadata.Add(nameof(error), error);
|
||||
tracer.RelatedWarning(
|
||||
metadata,
|
||||
"Failed to create service UI logs directory",
|
||||
Keywords.Telemetry);
|
||||
}
|
||||
else
|
||||
{
|
||||
string logFilePath = ScalarEnlistment.GetNewScalarLogFileName(
|
||||
serviceUILogDirectory,
|
||||
ScalarConstants.LogFileTypes.ServiceUI,
|
||||
logId: Environment.UserName);
|
||||
|
||||
tracer.AddLogFileEventListener(logFilePath, EventLevel.Informational, Keywords.Any);
|
||||
}
|
||||
|
||||
WinToastNotifier winToastNotifier = new WinToastNotifier(tracer);
|
||||
ScalarToastRequestHandler toastRequestHandler = new ScalarToastRequestHandler(winToastNotifier, tracer);
|
||||
GVFSServiceUI process = new GVFSServiceUI(tracer, toastRequestHandler);
|
||||
|
||||
process.Start(args);
|
||||
}
|
||||
}
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
ScalarPlatformLoader.Initialize();
|
||||
|
||||
using (JsonTracer tracer = new JsonTracer("Microsoft.Git.GVFS.Service.UI", "Service.UI"))
|
||||
{
|
||||
string error;
|
||||
string serviceUILogDirectory = ScalarPlatform.Instance.GetLogsDirectoryForGVFSComponent(ScalarConstants.Service.UIName);
|
||||
if (!ScalarPlatform.Instance.FileSystem.TryCreateDirectoryWithAdminAndUserModifyPermissions(serviceUILogDirectory, out error))
|
||||
{
|
||||
EventMetadata metadata = new EventMetadata();
|
||||
metadata.Add(nameof(serviceUILogDirectory), serviceUILogDirectory);
|
||||
metadata.Add(nameof(error), error);
|
||||
tracer.RelatedWarning(
|
||||
metadata,
|
||||
"Failed to create service UI logs directory",
|
||||
Keywords.Telemetry);
|
||||
}
|
||||
else
|
||||
{
|
||||
string logFilePath = ScalarEnlistment.GetNewScalarLogFileName(
|
||||
serviceUILogDirectory,
|
||||
ScalarConstants.LogFileTypes.ServiceUI,
|
||||
logId: Environment.UserName);
|
||||
|
||||
tracer.AddLogFileEventListener(logFilePath, EventLevel.Informational, Keywords.Any);
|
||||
}
|
||||
|
||||
WinToastNotifier winToastNotifier = new WinToastNotifier(tracer);
|
||||
ScalarToastRequestHandler toastRequestHandler = new ScalarToastRequestHandler(winToastNotifier, tracer);
|
||||
GVFSServiceUI process = new GVFSServiceUI(tracer, toastRequestHandler);
|
||||
|
||||
process.Start(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,61 @@
|
|||
using Scalar.Common;
|
||||
using Scalar.Common.NamedPipes;
|
||||
using Scalar.Common.Tracing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public class GVFSServiceUI
|
||||
{
|
||||
private readonly ITracer tracer;
|
||||
private readonly ScalarToastRequestHandler toastRequestHandler;
|
||||
|
||||
public GVFSServiceUI(ITracer tracer, ScalarToastRequestHandler toastRequestHandler)
|
||||
{
|
||||
this.tracer = tracer;
|
||||
this.toastRequestHandler = toastRequestHandler;
|
||||
}
|
||||
|
||||
public void Start(string[] args)
|
||||
{
|
||||
using (ITracer activity = this.tracer.StartActivity("Start", EventLevel.Informational))
|
||||
using (NamedPipeServer server = NamedPipeServer.StartNewServer(ScalarConstants.Service.UIName, this.tracer, this.HandleRequest))
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
mre.WaitOne();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleRequest(ITracer tracer, string request, NamedPipeServer.Connection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
NamedPipeMessages.Message message = NamedPipeMessages.Message.FromString(request);
|
||||
switch (message.Header)
|
||||
{
|
||||
case NamedPipeMessages.Notification.Request.Header:
|
||||
NamedPipeMessages.Notification.Request toastRequest = NamedPipeMessages.Notification.Request.FromMessage(message);
|
||||
if (toastRequest != null)
|
||||
{
|
||||
using (ITracer activity = this.tracer.StartActivity("SendToast", EventLevel.Informational))
|
||||
{
|
||||
this.toastRequestHandler.HandleToastRequest(activity, toastRequest);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.tracer.RelatedError("Unhandled exception: {0}", e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using Scalar.Common;
|
||||
using Scalar.Common.NamedPipes;
|
||||
using Scalar.Common.Tracing;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public class GVFSServiceUI
|
||||
{
|
||||
private readonly ITracer tracer;
|
||||
private readonly ScalarToastRequestHandler toastRequestHandler;
|
||||
|
||||
public GVFSServiceUI(ITracer tracer, ScalarToastRequestHandler toastRequestHandler)
|
||||
{
|
||||
this.tracer = tracer;
|
||||
this.toastRequestHandler = toastRequestHandler;
|
||||
}
|
||||
|
||||
public void Start(string[] args)
|
||||
{
|
||||
using (ITracer activity = this.tracer.StartActivity("Start", EventLevel.Informational))
|
||||
using (NamedPipeServer server = NamedPipeServer.StartNewServer(ScalarConstants.Service.UIName, this.tracer, this.HandleRequest))
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
mre.WaitOne();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleRequest(ITracer tracer, string request, NamedPipeServer.Connection connection)
|
||||
{
|
||||
try
|
||||
{
|
||||
NamedPipeMessages.Message message = NamedPipeMessages.Message.FromString(request);
|
||||
switch (message.Header)
|
||||
{
|
||||
case NamedPipeMessages.Notification.Request.Header:
|
||||
NamedPipeMessages.Notification.Request toastRequest = NamedPipeMessages.Notification.Request.FromMessage(message);
|
||||
if (toastRequest != null)
|
||||
{
|
||||
using (ITracer activity = this.tracer.StartActivity("SendToast", EventLevel.Informational))
|
||||
{
|
||||
this.toastRequestHandler.HandleToastRequest(activity, toastRequest);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.tracer.RelatedError("Unhandled exception: {0}", e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,103 +1,103 @@
|
|||
using Scalar.Common;
|
||||
using Scalar.Common.Tracing;
|
||||
using Scalar.Service.UI.Data;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Windows.UI.Notifications;
|
||||
using XmlDocument = Windows.Data.Xml.Dom.XmlDocument;
|
||||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public class WinToastNotifier : IToastNotifier
|
||||
{
|
||||
private const string ServiceAppId = "Scalar";
|
||||
private const string ScalarIconName = "scalar.ico";
|
||||
private ITracer tracer;
|
||||
|
||||
public WinToastNotifier(ITracer tracer)
|
||||
{
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
public Action<string> UserResponseCallback { get; set; }
|
||||
|
||||
public void Notify(string title, string message, string actionButtonTitle, string callbackArgs)
|
||||
{
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts
|
||||
ToastData toastData = new ToastData();
|
||||
|
||||
toastData.Visual = new VisualData();
|
||||
|
||||
BindingData binding = new BindingData();
|
||||
toastData.Visual.Binding = binding;
|
||||
|
||||
// ToastGeneric- Our toast contains VFSForGit icon and text
|
||||
binding.Template = "ToastGeneric";
|
||||
binding.Items = new XmlList<BindingItem>();
|
||||
binding.Items.Add(new BindingItem.TextData(title));
|
||||
binding.Items.Add(new BindingItem.TextData(message));
|
||||
|
||||
string logo = "file:///" + Path.Combine(ProcessHelper.GetCurrentProcessLocation(), ScalarIconName);
|
||||
binding.Items.Add(new BindingItem.ImageData()
|
||||
{
|
||||
Source = logo,
|
||||
Placement = "appLogoOverride",
|
||||
HintCrop = "circle"
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(actionButtonTitle))
|
||||
{
|
||||
ActionsData actionsData = new ActionsData();
|
||||
actionsData.Actions = new XmlList<ActionItem>();
|
||||
actionsData.Actions.Add(new ActionItem()
|
||||
{
|
||||
Content = actionButtonTitle,
|
||||
Arguments = string.IsNullOrEmpty(callbackArgs) ? string.Empty : callbackArgs,
|
||||
ActivationType = "background"
|
||||
});
|
||||
|
||||
toastData.Actions = actionsData;
|
||||
}
|
||||
|
||||
XmlDocument toastXml = new XmlDocument();
|
||||
using (StringWriter stringWriter = new StringWriter())
|
||||
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { OmitXmlDeclaration = true }))
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(toastData.GetType());
|
||||
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
|
||||
namespaces.Add(string.Empty, string.Empty);
|
||||
|
||||
serializer.Serialize(xmlWriter, toastData, namespaces);
|
||||
|
||||
toastXml.LoadXml(stringWriter.ToString());
|
||||
}
|
||||
|
||||
ToastNotification toastNotification = new ToastNotification(toastXml);
|
||||
toastNotification.Activated += this.ToastActivated;
|
||||
toastNotification.Dismissed += this.ToastDismissed;
|
||||
toastNotification.Failed += this.ToastFailed;
|
||||
|
||||
ToastNotifier toastNotifier = ToastNotificationManager.CreateToastNotifier(ServiceAppId);
|
||||
toastNotifier.Show(toastNotification);
|
||||
}
|
||||
|
||||
private void ToastActivated(ToastNotification sender, object e)
|
||||
{
|
||||
ToastActivatedEventArgs args = (ToastActivatedEventArgs)e;
|
||||
|
||||
this.UserResponseCallback?.Invoke(args.Arguments);
|
||||
}
|
||||
|
||||
private void ToastDismissed(ToastNotification sender, ToastDismissedEventArgs e)
|
||||
{
|
||||
this.tracer.RelatedInfo($"{nameof(this.ToastDismissed)}: {e.Reason}");
|
||||
}
|
||||
|
||||
private void ToastFailed(ToastNotification sender, ToastFailedEventArgs e)
|
||||
{
|
||||
this.tracer.RelatedInfo($"{nameof(this.ToastFailed)}: {e.ErrorCode.ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
using Scalar.Common;
|
||||
using Scalar.Common.Tracing;
|
||||
using Scalar.Service.UI.Data;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using Windows.UI.Notifications;
|
||||
using XmlDocument = Windows.Data.Xml.Dom.XmlDocument;
|
||||
|
||||
namespace Scalar.Service.UI
|
||||
{
|
||||
public class WinToastNotifier : IToastNotifier
|
||||
{
|
||||
private const string ServiceAppId = "Scalar";
|
||||
private const string ScalarIconName = "scalar.ico";
|
||||
private ITracer tracer;
|
||||
|
||||
public WinToastNotifier(ITracer tracer)
|
||||
{
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
public Action<string> UserResponseCallback { get; set; }
|
||||
|
||||
public void Notify(string title, string message, string actionButtonTitle, string callbackArgs)
|
||||
{
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts
|
||||
ToastData toastData = new ToastData();
|
||||
|
||||
toastData.Visual = new VisualData();
|
||||
|
||||
BindingData binding = new BindingData();
|
||||
toastData.Visual.Binding = binding;
|
||||
|
||||
// ToastGeneric- Our toast contains VFSForGit icon and text
|
||||
binding.Template = "ToastGeneric";
|
||||
binding.Items = new XmlList<BindingItem>();
|
||||
binding.Items.Add(new BindingItem.TextData(title));
|
||||
binding.Items.Add(new BindingItem.TextData(message));
|
||||
|
||||
string logo = "file:///" + Path.Combine(ProcessHelper.GetCurrentProcessLocation(), ScalarIconName);
|
||||
binding.Items.Add(new BindingItem.ImageData()
|
||||
{
|
||||
Source = logo,
|
||||
Placement = "appLogoOverride",
|
||||
HintCrop = "circle"
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(actionButtonTitle))
|
||||
{
|
||||
ActionsData actionsData = new ActionsData();
|
||||
actionsData.Actions = new XmlList<ActionItem>();
|
||||
actionsData.Actions.Add(new ActionItem()
|
||||
{
|
||||
Content = actionButtonTitle,
|
||||
Arguments = string.IsNullOrEmpty(callbackArgs) ? string.Empty : callbackArgs,
|
||||
ActivationType = "background"
|
||||
});
|
||||
|
||||
toastData.Actions = actionsData;
|
||||
}
|
||||
|
||||
XmlDocument toastXml = new XmlDocument();
|
||||
using (StringWriter stringWriter = new StringWriter())
|
||||
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { OmitXmlDeclaration = true }))
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(toastData.GetType());
|
||||
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
|
||||
namespaces.Add(string.Empty, string.Empty);
|
||||
|
||||
serializer.Serialize(xmlWriter, toastData, namespaces);
|
||||
|
||||
toastXml.LoadXml(stringWriter.ToString());
|
||||
}
|
||||
|
||||
ToastNotification toastNotification = new ToastNotification(toastXml);
|
||||
toastNotification.Activated += this.ToastActivated;
|
||||
toastNotification.Dismissed += this.ToastDismissed;
|
||||
toastNotification.Failed += this.ToastFailed;
|
||||
|
||||
ToastNotifier toastNotifier = ToastNotificationManager.CreateToastNotifier(ServiceAppId);
|
||||
toastNotifier.Show(toastNotification);
|
||||
}
|
||||
|
||||
private void ToastActivated(ToastNotification sender, object e)
|
||||
{
|
||||
ToastActivatedEventArgs args = (ToastActivatedEventArgs)e;
|
||||
|
||||
this.UserResponseCallback?.Invoke(args.Arguments);
|
||||
}
|
||||
|
||||
private void ToastDismissed(ToastNotification sender, ToastDismissedEventArgs e)
|
||||
{
|
||||
this.tracer.RelatedInfo($"{nameof(this.ToastDismissed)}: {e.Reason}");
|
||||
}
|
||||
|
||||
private void ToastFailed(ToastNotification sender, ToastFailedEventArgs e)
|
||||
{
|
||||
this.tracer.RelatedInfo($"{nameof(this.ToastFailed)}: {e.ErrorCode.ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,9 @@ namespace Scalar.Service
|
|||
{
|
||||
if (!ScalarEnlistment.IsUnattended(this.tracer))
|
||||
{
|
||||
// Adding 60 seconds wait time here. This gives VFSForGit installer/upgrader
|
||||
// sufficient enough time to launch GVFS.Service.UI that is needed to display
|
||||
// Upgrade available toaster.
|
||||
// Adding 60 seconds wait time here. This gives VFSForGit installer/upgrader
|
||||
// sufficient enough time to launch GVFS.Service.UI that is needed to display
|
||||
// Upgrade available toaster.
|
||||
TimeSpan startTime = TimeSpan.FromSeconds(60);
|
||||
|
||||
this.tracer.RelatedInfo("Starting auto upgrade checks.");
|
||||
|
@ -193,13 +193,13 @@ namespace Scalar.Service
|
|||
return true;
|
||||
}
|
||||
|
||||
private void DisplayUpgradeAvailableToast(string version)
|
||||
{
|
||||
NamedPipeMessages.Notification.Request request = new NamedPipeMessages.Notification.Request();
|
||||
request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable;
|
||||
request.NewVersion = version;
|
||||
|
||||
this.notificationHandler.SendNotification(request);
|
||||
private void DisplayUpgradeAvailableToast(string version)
|
||||
{
|
||||
NamedPipeMessages.Notification.Request request = new NamedPipeMessages.Notification.Request();
|
||||
request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable;
|
||||
request.NewVersion = version;
|
||||
|
||||
this.notificationHandler.SendNotification(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using Scalar.Common.Tracing;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Scalar.Common;
|
||||
|
|
|
@ -1,75 +1,75 @@
|
|||
using Moq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Scalar.Common.NamedPipes;
|
||||
using Scalar.Service.UI;
|
||||
using Scalar.UnitTests.Mock.Common;
|
||||
using System;
|
||||
|
||||
namespace Scalar.UnitTests.Windows.ServiceUI
|
||||
{
|
||||
[TestFixture]
|
||||
public class ScalarToastRequestHandlerTests
|
||||
{
|
||||
private NamedPipeMessages.Notification.Request request;
|
||||
private ScalarToastRequestHandler toastHandler;
|
||||
private Mock<IToastNotifier> mockToastNotifier;
|
||||
private MockTracer tracer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
this.tracer = new MockTracer();
|
||||
this.mockToastNotifier = new Mock<IToastNotifier>(MockBehavior.Strict);
|
||||
this.mockToastNotifier.SetupSet(toastNotifier => toastNotifier.UserResponseCallback = It.IsAny<Action<string>>()).Verifiable();
|
||||
this.toastHandler = new ScalarToastRequestHandler(this.mockToastNotifier.Object, this.tracer);
|
||||
this.request = new NamedPipeMessages.Notification.Request();
|
||||
}
|
||||
|
||||
[TestCase]
|
||||
public void UpgradeToastIsActionableAndContainsVersionInfo()
|
||||
{
|
||||
const string version = "1.0.956749.2";
|
||||
|
||||
this.request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable;
|
||||
this.request.NewVersion = version;
|
||||
|
||||
this.VerifyToastMessage(
|
||||
expectedTitle: "New version " + version + " is available",
|
||||
expectedMessage: "click Upgrade button",
|
||||
expectedButtonTitle: "Upgrade",
|
||||
expectedScalarCmd: "scalar upgrade --confirm");
|
||||
}
|
||||
|
||||
[TestCase]
|
||||
public void UnknownToastRequestGetsIgnored()
|
||||
{
|
||||
this.request.Id = (NamedPipeMessages.Notification.Request.Identifier)10;
|
||||
|
||||
this.toastHandler.HandleToastRequest(this.tracer, this.request);
|
||||
|
||||
this.mockToastNotifier.Verify(
|
||||
toastNotifier => toastNotifier.Notify(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>()),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
private void VerifyToastMessage(
|
||||
string expectedTitle,
|
||||
string expectedMessage,
|
||||
string expectedButtonTitle,
|
||||
string expectedScalarCmd)
|
||||
{
|
||||
this.mockToastNotifier.Setup(toastNotifier => toastNotifier.Notify(
|
||||
expectedTitle,
|
||||
It.Is<string>(message => message.Contains(expectedMessage)),
|
||||
expectedButtonTitle,
|
||||
expectedScalarCmd));
|
||||
|
||||
this.toastHandler.HandleToastRequest(this.tracer, this.request);
|
||||
this.mockToastNotifier.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
using Scalar.Common.NamedPipes;
|
||||
using Scalar.Service.UI;
|
||||
using Scalar.UnitTests.Mock.Common;
|
||||
using System;
|
||||
|
||||
namespace Scalar.UnitTests.Windows.ServiceUI
|
||||
{
|
||||
[TestFixture]
|
||||
public class ScalarToastRequestHandlerTests
|
||||
{
|
||||
private NamedPipeMessages.Notification.Request request;
|
||||
private ScalarToastRequestHandler toastHandler;
|
||||
private Mock<IToastNotifier> mockToastNotifier;
|
||||
private MockTracer tracer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
this.tracer = new MockTracer();
|
||||
this.mockToastNotifier = new Mock<IToastNotifier>(MockBehavior.Strict);
|
||||
this.mockToastNotifier.SetupSet(toastNotifier => toastNotifier.UserResponseCallback = It.IsAny<Action<string>>()).Verifiable();
|
||||
this.toastHandler = new ScalarToastRequestHandler(this.mockToastNotifier.Object, this.tracer);
|
||||
this.request = new NamedPipeMessages.Notification.Request();
|
||||
}
|
||||
|
||||
[TestCase]
|
||||
public void UpgradeToastIsActionableAndContainsVersionInfo()
|
||||
{
|
||||
const string version = "1.0.956749.2";
|
||||
|
||||
this.request.Id = NamedPipeMessages.Notification.Request.Identifier.UpgradeAvailable;
|
||||
this.request.NewVersion = version;
|
||||
|
||||
this.VerifyToastMessage(
|
||||
expectedTitle: "New version " + version + " is available",
|
||||
expectedMessage: "click Upgrade button",
|
||||
expectedButtonTitle: "Upgrade",
|
||||
expectedScalarCmd: "scalar upgrade --confirm");
|
||||
}
|
||||
|
||||
[TestCase]
|
||||
public void UnknownToastRequestGetsIgnored()
|
||||
{
|
||||
this.request.Id = (NamedPipeMessages.Notification.Request.Identifier)10;
|
||||
|
||||
this.toastHandler.HandleToastRequest(this.tracer, this.request);
|
||||
|
||||
this.mockToastNotifier.Verify(
|
||||
toastNotifier => toastNotifier.Notify(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>()),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
private void VerifyToastMessage(
|
||||
string expectedTitle,
|
||||
string expectedMessage,
|
||||
string expectedButtonTitle,
|
||||
string expectedScalarCmd)
|
||||
{
|
||||
this.mockToastNotifier.Setup(toastNotifier => toastNotifier.Notify(
|
||||
expectedTitle,
|
||||
It.Is<string>(message => message.Contains(expectedMessage)),
|
||||
expectedButtonTitle,
|
||||
expectedScalarCmd));
|
||||
|
||||
this.toastHandler.HandleToastRequest(this.tracer, this.request);
|
||||
this.mockToastNotifier.VerifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
198
Scalar.sln
198
Scalar.sln
|
@ -1,99 +1,99 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30406.18
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar", "Scalar\Scalar.csproj", "{31208ED8-5B83-4BE6-802A-18EE67434537}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Common", "Scalar.Common\Scalar.Common.csproj", "{179EAE33-265B-4698-BBC7-130F28F6D768}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service", "Scalar.Service\Scalar.Service.csproj", "{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Upgrader", "Scalar.Upgrader\Scalar.Upgrader.csproj", "{424D0102-50EE-4CA6-A937-C8A89CE10103}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.UnitTests", "Scalar.UnitTests\Scalar.UnitTests.csproj", "{B1D1E8BE-D633-4624-A821-B222EB1B8020}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EB9427BB-456A-4319-8916-E782E0F5F6D3}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Dependencies.props = Dependencies.props
|
||||
Directory.Build.props = Directory.Build.props
|
||||
Directory.Build.targets = Directory.Build.targets
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.FunctionalTests", "Scalar.FunctionalTests\Scalar.FunctionalTests.csproj", "{C7E08779-6F45-4025-89E1-31346C9B234F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.TestInfrastructure", "Scalar.TestInfrastructure\Scalar.TestInfrastructure.csproj", "{77FC445D-FD03-4EE0-8582-7BD1437D9842}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.MSBuild", "Scalar.MSBuild\Scalar.MSBuild.csproj", "{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Mac", "Scalar.Installer.Mac\Scalar.Installer.Mac.csproj", "{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Windows", "Scalar.Installer.Windows\Scalar.Installer.Windows.csproj", "{913C7CBD-876C-45D8-B59E-D0849CD219E4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service.UI", "Scalar.Service.UI\Scalar.Service.UI.csproj", "{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Notifications.Mac", "Scalar.Notifications.Mac\Scalar.Notifications.Mac.csproj", "{ED367118-BFB1-41CA-A010-E46C28796ED8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FDE61E04-DC84-437F-A176-40CD62CDE05F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30406.18
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar", "Scalar\Scalar.csproj", "{31208ED8-5B83-4BE6-802A-18EE67434537}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Common", "Scalar.Common\Scalar.Common.csproj", "{179EAE33-265B-4698-BBC7-130F28F6D768}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service", "Scalar.Service\Scalar.Service.csproj", "{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Upgrader", "Scalar.Upgrader\Scalar.Upgrader.csproj", "{424D0102-50EE-4CA6-A937-C8A89CE10103}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.UnitTests", "Scalar.UnitTests\Scalar.UnitTests.csproj", "{B1D1E8BE-D633-4624-A821-B222EB1B8020}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EB9427BB-456A-4319-8916-E782E0F5F6D3}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Dependencies.props = Dependencies.props
|
||||
Directory.Build.props = Directory.Build.props
|
||||
Directory.Build.targets = Directory.Build.targets
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.FunctionalTests", "Scalar.FunctionalTests\Scalar.FunctionalTests.csproj", "{C7E08779-6F45-4025-89E1-31346C9B234F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.TestInfrastructure", "Scalar.TestInfrastructure\Scalar.TestInfrastructure.csproj", "{77FC445D-FD03-4EE0-8582-7BD1437D9842}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.MSBuild", "Scalar.MSBuild\Scalar.MSBuild.csproj", "{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Mac", "Scalar.Installer.Mac\Scalar.Installer.Mac.csproj", "{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Installer.Windows", "Scalar.Installer.Windows\Scalar.Installer.Windows.csproj", "{913C7CBD-876C-45D8-B59E-D0849CD219E4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Service.UI", "Scalar.Service.UI\Scalar.Service.UI.csproj", "{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scalar.Notifications.Mac", "Scalar.Notifications.Mac\Scalar.Notifications.Mac.csproj", "{ED367118-BFB1-41CA-A010-E46C28796ED8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{31208ED8-5B83-4BE6-802A-18EE67434537}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{179EAE33-265B-4698-BBC7-130F28F6D768}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E75C4E5C-4446-43A3-BDE0-C9C4297485FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{424D0102-50EE-4CA6-A937-C8A89CE10103}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B1D1E8BE-D633-4624-A821-B222EB1B8020}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C7E08779-6F45-4025-89E1-31346C9B234F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{77FC445D-FD03-4EE0-8582-7BD1437D9842}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6B05E1DE-1C67-48F7-9A2A-E109D7252CF2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5CFE04A9-F65A-4EEF-B237-7608D19A87DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{913C7CBD-876C-45D8-B59E-D0849CD219E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{32D8335E-E9E8-4AD8-BAE5-162F53AA4D72}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED367118-BFB1-41CA-A010-E46C28796ED8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FDE61E04-DC84-437F-A176-40CD62CDE05F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -113,11 +113,11 @@ namespace Scalar.CommandLine
|
|||
copySubFolders: true);
|
||||
}
|
||||
|
||||
// service ui
|
||||
this.CopyAllFiles(
|
||||
ScalarPlatform.Instance.GetCommonAppDataRootForScalar(),
|
||||
archiveFolderPath,
|
||||
ScalarConstants.Service.UIName,
|
||||
// service ui
|
||||
this.CopyAllFiles(
|
||||
ScalarPlatform.Instance.GetCommonAppDataRootForScalar(),
|
||||
archiveFolderPath,
|
||||
ScalarConstants.Service.UIName,
|
||||
copySubFolders: true);
|
||||
|
||||
if (ScalarPlatform.Instance.UnderConstruction.UsesCustomUpgrader)
|
||||
|
|
138
docs/advanced.md
138
docs/advanced.md
|
@ -1,69 +1,69 @@
|
|||
Advanced Features
|
||||
=================
|
||||
|
||||
Run Maintenance in the Foreground
|
||||
---------------------------------
|
||||
|
||||
Scalar runs maintenance on your repositories in the background. You could
|
||||
chose to run those maintenance steps yourself by running `scalar run <task> [<options>]`.
|
||||
This command will run one maintenance step as specified by `<task>`. These
|
||||
tasks are:
|
||||
|
||||
* `config`: Set recommended Git config settings. These are all intended
|
||||
to improve performance in large repos. If the repo was cloned by Scalar,
|
||||
then most of these settings will overwrite any existing settings. Otherwise,
|
||||
Scalar will not override a local config value that disagrees with the
|
||||
recommendation.
|
||||
|
||||
* `commit-graph`: Update the Git commit-graph to include all reachable
|
||||
commits. After writing a new file, verify the file was computed successfully.
|
||||
This drastically improves the performance of commands like `git log --graph`.
|
||||
|
||||
* `fetch`: Fetch the latest data from the remote servers. If using the GVFS
|
||||
protocol, download the latest set of commit and tree packs from
|
||||
the cache server or the origin remote. Otherwise, this step will fetch
|
||||
the latest objects from each remote. This will not update your local
|
||||
refs, so your `git fetch` commands will report all ref updates. Those
|
||||
`git fetch` commands will be much faster as they will require much less
|
||||
data transfer.
|
||||
|
||||
* `loose-objects`: Examine the loose objects contained in the shared object
|
||||
cache. First, delete any loose objects that are currently located in
|
||||
pack-files. Second, create a new pack-file containing the remaining loose
|
||||
objects. The pack will contain up to 50,000 objects, leaving any extra
|
||||
objects for the next run of the `loose-objects` step. This happens in the
|
||||
background once a day.
|
||||
|
||||
* `pack-files`: Update the Git multi-pack-index and repack small pack-files
|
||||
into larger pack-files. Scalar downloads many pack-files during the
|
||||
`fetch` step, or during `git checkout` commands. The `pack-files`
|
||||
step updates the Git multi-pack-index to improve lookup speed. Further, it
|
||||
combines pack-files into larger files to reduce the total pack-file count.
|
||||
This step is designed to work without blocking concurrent processes by only
|
||||
deleting pack-files after they were marked as "unused" for at least a day.
|
||||
This step allows using the `--batch-size=<size>` option. By default, the
|
||||
batch-size is "2g" for two gigabytes. This batch size signifies the goal
|
||||
size of a repacked pack-file.
|
||||
|
||||
* `all`: This task runs all of the above steps in the following order:
|
||||
1. `config` ensures our recommended values are set for the remaining steps.
|
||||
2. `fetch` downloads the latest data from the remotes.
|
||||
3. `commit-graph` updates based on the newly fetched data.
|
||||
4. `loose-objects` cleans up loose objects. When using the GVFS protocol,
|
||||
the previous steps may have downloaded new loose objects.
|
||||
5. `pack-files` cleans up the pack-files, including those downloaed in
|
||||
previous steps.
|
||||
|
||||
Controlling Background Maintenance
|
||||
----------------------------------
|
||||
|
||||
If you have a need to temporarily pause background maintenance from running,
|
||||
then you can run `scalar pause [<number>]` to stop all maintenance for
|
||||
`<number>` hours. If `<number>` is not provided, then maintenance will be
|
||||
delayed for 12 hours.
|
||||
|
||||
For example, you may want to pause maintenance if you need all CPU resources
|
||||
on your machine available for a high-performance activity or for performance
|
||||
testing. You may also want to pause maintenance if you are on a metered
|
||||
internet connection, as some of the maintenance downloads Git data from the
|
||||
remote server.
|
||||
Advanced Features
|
||||
=================
|
||||
|
||||
Run Maintenance in the Foreground
|
||||
---------------------------------
|
||||
|
||||
Scalar runs maintenance on your repositories in the background. You could
|
||||
chose to run those maintenance steps yourself by running `scalar run <task> [<options>]`.
|
||||
This command will run one maintenance step as specified by `<task>`. These
|
||||
tasks are:
|
||||
|
||||
* `config`: Set recommended Git config settings. These are all intended
|
||||
to improve performance in large repos. If the repo was cloned by Scalar,
|
||||
then most of these settings will overwrite any existing settings. Otherwise,
|
||||
Scalar will not override a local config value that disagrees with the
|
||||
recommendation.
|
||||
|
||||
* `commit-graph`: Update the Git commit-graph to include all reachable
|
||||
commits. After writing a new file, verify the file was computed successfully.
|
||||
This drastically improves the performance of commands like `git log --graph`.
|
||||
|
||||
* `fetch`: Fetch the latest data from the remote servers. If using the GVFS
|
||||
protocol, download the latest set of commit and tree packs from
|
||||
the cache server or the origin remote. Otherwise, this step will fetch
|
||||
the latest objects from each remote. This will not update your local
|
||||
refs, so your `git fetch` commands will report all ref updates. Those
|
||||
`git fetch` commands will be much faster as they will require much less
|
||||
data transfer.
|
||||
|
||||
* `loose-objects`: Examine the loose objects contained in the shared object
|
||||
cache. First, delete any loose objects that are currently located in
|
||||
pack-files. Second, create a new pack-file containing the remaining loose
|
||||
objects. The pack will contain up to 50,000 objects, leaving any extra
|
||||
objects for the next run of the `loose-objects` step. This happens in the
|
||||
background once a day.
|
||||
|
||||
* `pack-files`: Update the Git multi-pack-index and repack small pack-files
|
||||
into larger pack-files. Scalar downloads many pack-files during the
|
||||
`fetch` step, or during `git checkout` commands. The `pack-files`
|
||||
step updates the Git multi-pack-index to improve lookup speed. Further, it
|
||||
combines pack-files into larger files to reduce the total pack-file count.
|
||||
This step is designed to work without blocking concurrent processes by only
|
||||
deleting pack-files after they were marked as "unused" for at least a day.
|
||||
This step allows using the `--batch-size=<size>` option. By default, the
|
||||
batch-size is "2g" for two gigabytes. This batch size signifies the goal
|
||||
size of a repacked pack-file.
|
||||
|
||||
* `all`: This task runs all of the above steps in the following order:
|
||||
1. `config` ensures our recommended values are set for the remaining steps.
|
||||
2. `fetch` downloads the latest data from the remotes.
|
||||
3. `commit-graph` updates based on the newly fetched data.
|
||||
4. `loose-objects` cleans up loose objects. When using the GVFS protocol,
|
||||
the previous steps may have downloaded new loose objects.
|
||||
5. `pack-files` cleans up the pack-files, including those downloaed in
|
||||
previous steps.
|
||||
|
||||
Controlling Background Maintenance
|
||||
----------------------------------
|
||||
|
||||
If you have a need to temporarily pause background maintenance from running,
|
||||
then you can run `scalar pause [<number>]` to stop all maintenance for
|
||||
`<number>` hours. If `<number>` is not provided, then maintenance will be
|
||||
delayed for 12 hours.
|
||||
|
||||
For example, you may want to pause maintenance if you need all CPU resources
|
||||
on your machine available for a high-performance activity or for performance
|
||||
testing. You may also want to pause maintenance if you are on a metered
|
||||
internet connection, as some of the maintenance downloads Git data from the
|
||||
remote server.
|
||||
|
|
174
docs/faq.md
174
docs/faq.md
|
@ -1,87 +1,87 @@
|
|||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
Using Scalar
|
||||
------------
|
||||
|
||||
### I don't want a sparse clone, I want every file after I clone!
|
||||
|
||||
Run `scalar clone --full-clone <url>` to initialize your repo to include
|
||||
every file. You can switch to a sparse-checkout later by running
|
||||
`git sparse-checkout init --cone`.
|
||||
|
||||
### I already cloned without `--full-clone`. How do I get everything?
|
||||
|
||||
Run `git sparse-checkout disable`.
|
||||
|
||||
Scalar Design Decisions
|
||||
-----------------------
|
||||
|
||||
There may be many design decisions within Scalar that are confusing at first
|
||||
glance. Some of them may cause friction when you use Scalar with your existing
|
||||
repos and existing habits.
|
||||
|
||||
> Scalar has the most benefit when users design repositories
|
||||
> with efficient patterns.
|
||||
|
||||
For example: Scalar uses the sparse-checkout feature to limit the size of the
|
||||
working directory within a large monorepo. It is designed to work efficiently
|
||||
with monorepos that are highly componentized, allowing most developers to
|
||||
need many fewer files in their daily work.
|
||||
|
||||
### Why does `scalar clone` create a `<repo>/src` folder?
|
||||
|
||||
Scalar uses a file system watcher to keep track of changes under this `src` folder.
|
||||
Any activity in this folder is assumed to be important to Git operations. By
|
||||
creating the `src` folder, we are making it easy for your build system to
|
||||
create output folders outside the `src` directory. We commonly see systems
|
||||
create folders for build outputs and package downloads. Scalar itself creates
|
||||
these folders during its builds.
|
||||
|
||||
Your build system may create build artifacts such as `.obj` or `.lib` files
|
||||
next to your source code. These are commonly "hidden" from Git using
|
||||
`.gitignore` files. Having such artifacts into your source tree creates
|
||||
additional work for Git because it needs to look at these files and match them
|
||||
against the `.gitignore` patterns.
|
||||
|
||||
By following the pattern Scalar tries to establish and placing your build
|
||||
intermediates and outputs parallel with the `src` folder and not inside it,
|
||||
you can help optimize Git command performance for developers in the repository
|
||||
by limiting the number of files Git needs to consider for many common
|
||||
operations.
|
||||
|
||||
### Why is Scalar a C# tool instead of built directly into Git?
|
||||
|
||||
Currently, Scalar does a few things that Git does not do and a few
|
||||
things that Git will never do.
|
||||
|
||||
Git does not have a concept of running background jobs, which is critical to
|
||||
keeping our repositories running smoothly. Git does not have a concept of
|
||||
cache servers, so we need to use the GVFS protocol during `scalar clone` to
|
||||
set up the cache server URL. Scalar also creates the `.scalarCache` directory
|
||||
so multiple enlistments share objects from the remote, allowing a second
|
||||
`scalar clone` operation to be much faster than the first. All of these concepts
|
||||
are on our backlog for contributing to Git. Once we do, we will transition
|
||||
from the Scalar implementation to the Git implementation.
|
||||
|
||||
Scalar uses the GVFS protocol for some repositories. This protocol was created
|
||||
by Azure Repos to support large repositories before the Git protocol supported
|
||||
partial clone and the Git client supported missing objects. In a way, the GVFS
|
||||
protocol proved that there was value in creating the partial clone feature.
|
||||
This shows precedent for how our C# tools show value that leads to Git client
|
||||
features. However, Git will never adopt the GVFS protocol, so we need to use
|
||||
an tool other than the Git client to support teams that use it.
|
||||
|
||||
For now, Scalar requires a
|
||||
[custom version of Git](https://github.com/microsoft/git), but we hope to relax
|
||||
that restriction eventually.
|
||||
We try to keep our fork of Git as close to [upstream](https://github.com/git-for-windows/git)
|
||||
as we can, but some patches are necessary _for now_. Still, maintaining those
|
||||
patches as we take updates from upstream has a significant cost. It is better
|
||||
to create features in C# that use Git as a black box, then remove those C#
|
||||
features as we contribute replacements to Git upstream.
|
||||
|
||||
Finally, as Git gains the features that we need in Scalar, Scalar will need to
|
||||
support backwards compatibility with repositories cloned with older versions of
|
||||
Scalar. Using the C# layer, we can update the Git version and upgrade old
|
||||
repositories to whatever new features are added to Git.
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
Using Scalar
|
||||
------------
|
||||
|
||||
### I don't want a sparse clone, I want every file after I clone!
|
||||
|
||||
Run `scalar clone --full-clone <url>` to initialize your repo to include
|
||||
every file. You can switch to a sparse-checkout later by running
|
||||
`git sparse-checkout init --cone`.
|
||||
|
||||
### I already cloned without `--full-clone`. How do I get everything?
|
||||
|
||||
Run `git sparse-checkout disable`.
|
||||
|
||||
Scalar Design Decisions
|
||||
-----------------------
|
||||
|
||||
There may be many design decisions within Scalar that are confusing at first
|
||||
glance. Some of them may cause friction when you use Scalar with your existing
|
||||
repos and existing habits.
|
||||
|
||||
> Scalar has the most benefit when users design repositories
|
||||
> with efficient patterns.
|
||||
|
||||
For example: Scalar uses the sparse-checkout feature to limit the size of the
|
||||
working directory within a large monorepo. It is designed to work efficiently
|
||||
with monorepos that are highly componentized, allowing most developers to
|
||||
need many fewer files in their daily work.
|
||||
|
||||
### Why does `scalar clone` create a `<repo>/src` folder?
|
||||
|
||||
Scalar uses a file system watcher to keep track of changes under this `src` folder.
|
||||
Any activity in this folder is assumed to be important to Git operations. By
|
||||
creating the `src` folder, we are making it easy for your build system to
|
||||
create output folders outside the `src` directory. We commonly see systems
|
||||
create folders for build outputs and package downloads. Scalar itself creates
|
||||
these folders during its builds.
|
||||
|
||||
Your build system may create build artifacts such as `.obj` or `.lib` files
|
||||
next to your source code. These are commonly "hidden" from Git using
|
||||
`.gitignore` files. Having such artifacts into your source tree creates
|
||||
additional work for Git because it needs to look at these files and match them
|
||||
against the `.gitignore` patterns.
|
||||
|
||||
By following the pattern Scalar tries to establish and placing your build
|
||||
intermediates and outputs parallel with the `src` folder and not inside it,
|
||||
you can help optimize Git command performance for developers in the repository
|
||||
by limiting the number of files Git needs to consider for many common
|
||||
operations.
|
||||
|
||||
### Why is Scalar a C# tool instead of built directly into Git?
|
||||
|
||||
Currently, Scalar does a few things that Git does not do and a few
|
||||
things that Git will never do.
|
||||
|
||||
Git does not have a concept of running background jobs, which is critical to
|
||||
keeping our repositories running smoothly. Git does not have a concept of
|
||||
cache servers, so we need to use the GVFS protocol during `scalar clone` to
|
||||
set up the cache server URL. Scalar also creates the `.scalarCache` directory
|
||||
so multiple enlistments share objects from the remote, allowing a second
|
||||
`scalar clone` operation to be much faster than the first. All of these concepts
|
||||
are on our backlog for contributing to Git. Once we do, we will transition
|
||||
from the Scalar implementation to the Git implementation.
|
||||
|
||||
Scalar uses the GVFS protocol for some repositories. This protocol was created
|
||||
by Azure Repos to support large repositories before the Git protocol supported
|
||||
partial clone and the Git client supported missing objects. In a way, the GVFS
|
||||
protocol proved that there was value in creating the partial clone feature.
|
||||
This shows precedent for how our C# tools show value that leads to Git client
|
||||
features. However, Git will never adopt the GVFS protocol, so we need to use
|
||||
an tool other than the Git client to support teams that use it.
|
||||
|
||||
For now, Scalar requires a
|
||||
[custom version of Git](https://github.com/microsoft/git), but we hope to relax
|
||||
that restriction eventually.
|
||||
We try to keep our fork of Git as close to [upstream](https://github.com/git-for-windows/git)
|
||||
as we can, but some patches are necessary _for now_. Still, maintaining those
|
||||
patches as we take updates from upstream has a significant cost. It is better
|
||||
to create features in C# that use Git as a black box, then remove those C#
|
||||
features as we contribute replacements to Git upstream.
|
||||
|
||||
Finally, as Git gains the features that we need in Scalar, Scalar will need to
|
||||
support backwards compatibility with repositories cloned with older versions of
|
||||
Scalar. Using the C# layer, we can update the Git version and upgrade old
|
||||
repositories to whatever new features are added to Git.
|
||||
|
|
|
@ -1,112 +1,112 @@
|
|||
Getting Started
|
||||
===============
|
||||
|
||||
Registering existing Git repos
|
||||
------------------------------
|
||||
|
||||
To add a repository to the list of registered repos, run `scalar register [<path>]`.
|
||||
If `<path>` is not provided, then the "current repository" is discovered from
|
||||
the working directory by scanning the parent paths for a path containing a `.git`
|
||||
folder, possibly inside a `src` folder.
|
||||
|
||||
To see which repositories are currently tracked by the service, run
|
||||
`scalar list`.
|
||||
|
||||
Run `scalar unregister [<path>]` to remove the repo from this list.
|
||||
|
||||
Creating a new Scalar clone using the GVFS Protocol
|
||||
---------------------------------------------------
|
||||
|
||||
The `clone` verb creates a local enlistment of a remote repository using the
|
||||
[GVFS protocol](https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md).
|
||||
|
||||
```
|
||||
scalar clone [options] <url> [<dir>]
|
||||
```
|
||||
|
||||
Create a local copy of the repository at `<url>`. If specified, create the `<dir>`
|
||||
directory and place the repository there. Otherwise, the last section of the `<url>`
|
||||
will be used for `<dir>`.
|
||||
|
||||
At the end, the repo is located at `<dir>/src`. By default, the sparse-checkout
|
||||
feature is enabled and the only files present are those in the root of your
|
||||
Git repository. Use `git sparse-checkout set` to expand the set of directories
|
||||
you want to see, or `git sparse-checkout disable` to expand to all files. You
|
||||
can explore the subdirectories outside your sparse-checkout specification using
|
||||
`git ls-tree HEAD`.
|
||||
|
||||
### Sparse Repo Mode
|
||||
|
||||
By default, Scalar reduces your working directory to the only the files at the
|
||||
root of the repository. You need to add the folders you care about to build up
|
||||
to your working set.
|
||||
|
||||
* `scalar clone <url>`
|
||||
* Please choose the **Clone with HTTPS** option in the `Clone Repository` dialog in Azure Repos, not **Clone with SSH**.
|
||||
* `cd <root>\src`
|
||||
* At this point, your `src` directory only contains files that appear in your root
|
||||
tree. No folders are populated.
|
||||
* Set the directory list for your sparse-checkout using:
|
||||
1. `git sparse-checkout set <dir1> <dir2> ...`
|
||||
2. `git sparse-checkout set --stdin <dir-list.txt`
|
||||
* Run git commands as you normally would.
|
||||
* To fully populate your working directory, run `git sparse-checkout disable`.
|
||||
|
||||
If instead you want to start with all files on-disk, you can clone with the
|
||||
`--full-clone` option. To enable sparse-checkout after the fact, run
|
||||
`git sparse-checkout init --cone`. This will initialize your sparse-checkout
|
||||
patterns to only match the files at root.
|
||||
|
||||
If you are unfamiliar with what directories are available in the repository,
|
||||
then you can run `git ls-tree -d --name-only HEAD` to discover the directories
|
||||
at root, or `git ls-tree -d --name-only HEAD <path>` to discover the directories
|
||||
in `<path>`.
|
||||
|
||||
### Options
|
||||
|
||||
These options allow a user to customize their initial enlistment.
|
||||
|
||||
* `--full-clone`: If specified, do not initialize the sparse-checkout feature.
|
||||
All files will be present in your `src` directory. This behaves very similar
|
||||
to a Git partial clone in that blobs are downloaded on demand. However, it
|
||||
will use the GVFS protocol to download all Git objects.
|
||||
|
||||
* `--cache-server-url=<url>`: If specified, set the intended cache server to
|
||||
the specified `<url>`. All object queries will use the GVFS protocol to this
|
||||
`<url>` instead of the origin remote. If the remote supplies a list of
|
||||
cache servers via the `<url>/gvfs/config` endpoint, then the `clone` command
|
||||
will select a nearby cache server from that list.
|
||||
|
||||
* `--branch=<ref>`: Specify the branch to checkout after clone.
|
||||
|
||||
* `--local-cache-path=<path>`: Use this option to override the path for the
|
||||
local Scalar cache. If not specified, then Scalar will select a default
|
||||
path to share objects with your other enlistments. On Windows, this path
|
||||
is a subdirectory of `<Volume>:\.scalarCache\`. On Mac, this path is a
|
||||
subdirectory of `~/.scalarCache/`. The default cache path is recommended so
|
||||
multiple enlistments of the same remote repository share objects on the
|
||||
same device.
|
||||
|
||||
### Advanced Options
|
||||
|
||||
The options below are not intended for use by a typical user. These are
|
||||
usually used by build machines to create a temporary enlistment that
|
||||
operates on a single commit.
|
||||
|
||||
* `--single-branch`: Use this option to only download metadata for the branch
|
||||
that will be checked out. This is helpful for build machines that target
|
||||
a remote with many branches. Any `git fetch` commands after the clone will
|
||||
still ask for all branches.
|
||||
|
||||
* `--no-prefetch`: Use this option to not prefetch commits after clone. This
|
||||
is not recommended for anyone planning to use their clone for history
|
||||
traversal. Use of this option will make commands like `git log` or
|
||||
`git pull` extremely slow and is therefore not recommended.
|
||||
|
||||
Removing a Scalar Clone
|
||||
-----------------------
|
||||
|
||||
Since the `scalar clone` command sets up a file-system watcher (when available),
|
||||
that watcher could prevent deleting the enlistment. Run `scalar delete <path>`
|
||||
from outside of your enlistment to unregister the enlistment from the filesystem
|
||||
watcher and delete the enlistment at `<path>`.
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
Registering existing Git repos
|
||||
------------------------------
|
||||
|
||||
To add a repository to the list of registered repos, run `scalar register [<path>]`.
|
||||
If `<path>` is not provided, then the "current repository" is discovered from
|
||||
the working directory by scanning the parent paths for a path containing a `.git`
|
||||
folder, possibly inside a `src` folder.
|
||||
|
||||
To see which repositories are currently tracked by the service, run
|
||||
`scalar list`.
|
||||
|
||||
Run `scalar unregister [<path>]` to remove the repo from this list.
|
||||
|
||||
Creating a new Scalar clone using the GVFS Protocol
|
||||
---------------------------------------------------
|
||||
|
||||
The `clone` verb creates a local enlistment of a remote repository using the
|
||||
[GVFS protocol](https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md).
|
||||
|
||||
```
|
||||
scalar clone [options] <url> [<dir>]
|
||||
```
|
||||
|
||||
Create a local copy of the repository at `<url>`. If specified, create the `<dir>`
|
||||
directory and place the repository there. Otherwise, the last section of the `<url>`
|
||||
will be used for `<dir>`.
|
||||
|
||||
At the end, the repo is located at `<dir>/src`. By default, the sparse-checkout
|
||||
feature is enabled and the only files present are those in the root of your
|
||||
Git repository. Use `git sparse-checkout set` to expand the set of directories
|
||||
you want to see, or `git sparse-checkout disable` to expand to all files. You
|
||||
can explore the subdirectories outside your sparse-checkout specification using
|
||||
`git ls-tree HEAD`.
|
||||
|
||||
### Sparse Repo Mode
|
||||
|
||||
By default, Scalar reduces your working directory to the only the files at the
|
||||
root of the repository. You need to add the folders you care about to build up
|
||||
to your working set.
|
||||
|
||||
* `scalar clone <url>`
|
||||
* Please choose the **Clone with HTTPS** option in the `Clone Repository` dialog in Azure Repos, not **Clone with SSH**.
|
||||
* `cd <root>\src`
|
||||
* At this point, your `src` directory only contains files that appear in your root
|
||||
tree. No folders are populated.
|
||||
* Set the directory list for your sparse-checkout using:
|
||||
1. `git sparse-checkout set <dir1> <dir2> ...`
|
||||
2. `git sparse-checkout set --stdin <dir-list.txt`
|
||||
* Run git commands as you normally would.
|
||||
* To fully populate your working directory, run `git sparse-checkout disable`.
|
||||
|
||||
If instead you want to start with all files on-disk, you can clone with the
|
||||
`--full-clone` option. To enable sparse-checkout after the fact, run
|
||||
`git sparse-checkout init --cone`. This will initialize your sparse-checkout
|
||||
patterns to only match the files at root.
|
||||
|
||||
If you are unfamiliar with what directories are available in the repository,
|
||||
then you can run `git ls-tree -d --name-only HEAD` to discover the directories
|
||||
at root, or `git ls-tree -d --name-only HEAD <path>` to discover the directories
|
||||
in `<path>`.
|
||||
|
||||
### Options
|
||||
|
||||
These options allow a user to customize their initial enlistment.
|
||||
|
||||
* `--full-clone`: If specified, do not initialize the sparse-checkout feature.
|
||||
All files will be present in your `src` directory. This behaves very similar
|
||||
to a Git partial clone in that blobs are downloaded on demand. However, it
|
||||
will use the GVFS protocol to download all Git objects.
|
||||
|
||||
* `--cache-server-url=<url>`: If specified, set the intended cache server to
|
||||
the specified `<url>`. All object queries will use the GVFS protocol to this
|
||||
`<url>` instead of the origin remote. If the remote supplies a list of
|
||||
cache servers via the `<url>/gvfs/config` endpoint, then the `clone` command
|
||||
will select a nearby cache server from that list.
|
||||
|
||||
* `--branch=<ref>`: Specify the branch to checkout after clone.
|
||||
|
||||
* `--local-cache-path=<path>`: Use this option to override the path for the
|
||||
local Scalar cache. If not specified, then Scalar will select a default
|
||||
path to share objects with your other enlistments. On Windows, this path
|
||||
is a subdirectory of `<Volume>:\.scalarCache\`. On Mac, this path is a
|
||||
subdirectory of `~/.scalarCache/`. The default cache path is recommended so
|
||||
multiple enlistments of the same remote repository share objects on the
|
||||
same device.
|
||||
|
||||
### Advanced Options
|
||||
|
||||
The options below are not intended for use by a typical user. These are
|
||||
usually used by build machines to create a temporary enlistment that
|
||||
operates on a single commit.
|
||||
|
||||
* `--single-branch`: Use this option to only download metadata for the branch
|
||||
that will be checked out. This is helpful for build machines that target
|
||||
a remote with many branches. Any `git fetch` commands after the clone will
|
||||
still ask for all branches.
|
||||
|
||||
* `--no-prefetch`: Use this option to not prefetch commits after clone. This
|
||||
is not recommended for anyone planning to use their clone for history
|
||||
traversal. Use of this option will make commands like `git log` or
|
||||
`git pull` extremely slow and is therefore not recommended.
|
||||
|
||||
Removing a Scalar Clone
|
||||
-----------------------
|
||||
|
||||
Since the `scalar clone` command sets up a file-system watcher (when available),
|
||||
that watcher could prevent deleting the enlistment. Run `scalar delete <path>`
|
||||
from outside of your enlistment to unregister the enlistment from the filesystem
|
||||
watcher and delete the enlistment at `<path>`.
|
||||
|
|
148
docs/index.md
148
docs/index.md
|
@ -1,74 +1,74 @@
|
|||
Scalar: Enabling Git at Scale
|
||||
=============================
|
||||
|
||||
Scalar is a tool that helps Git scale to some of the largest Git repositories.
|
||||
It achieves this by enabling some advanced Git features, such as:
|
||||
|
||||
* *Sparse-checkout:* limits the size of your working directory.
|
||||
|
||||
* *File system monitor:* tracks the recently modified files and eliminates
|
||||
the need for Git to scan the entire worktree.
|
||||
|
||||
* *Commit-graph:* accelerates commit walks and reachability calculations,
|
||||
speeding up commands like `git log`.
|
||||
|
||||
* *Multi-pack-index:* enables fast object lookups across many pack-files.
|
||||
|
||||
* *Incremental repack:* Repacks the packed Git data into fewer pack-file
|
||||
without disrupting concurrent commands by using the multi-pack-index.
|
||||
|
||||
By running `scalar register` in any Git repo, Scalar will automatically enable
|
||||
these features for that repo and start running suggested maintenance in the
|
||||
background.
|
||||
|
||||
Repos cloned with the `scalar clone` command use the
|
||||
[GVFS protocol](https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md)
|
||||
to significantly reduce the amount of data required to get started
|
||||
using a repository. By delaying all blob downloads until they are required,
|
||||
Scalar allows you to work with very large repositories quickly. This protocol
|
||||
allows a network of _cache servers_ to serve objects with lower latency and
|
||||
higher throughput. The cache servers also reduce load on the central server.
|
||||
|
||||
Installing on macOS
|
||||
------------------
|
||||
|
||||
To install Scalar on macOS,
|
||||
[download the `Installers_macOS_Release.zip` from the releases page](https://github.com/microsoft/scalar/releases).
|
||||
Extract the `Installers_macOS_Release` folder, `cd` into it, and run `./InstallScalar.sh` in a Terminal window.
|
||||
The script may prompt for your password as it installs the following components:
|
||||
|
||||
* [Git](https://github.com/microsoft/git) (with custom patches)
|
||||
* [Git Credential Manager Core](https://github.com/microsoft/Git-Credential-Manager-Core)
|
||||
* Scalar
|
||||
* [Watchman](https://github.com/facebook/watchman), unless you use the `--no-watchman` argument.
|
||||
|
||||
Installing on Windows
|
||||
--------------------
|
||||
|
||||
To install Scalar on Windows,
|
||||
[download the `Installers_Windows_Release.zip` from the releases page](https://github.com/microsoft/scalar/releases).
|
||||
Extract the `Installers_Windows_Release` folder, open it in a command prompt, and
|
||||
run `InstallScalar.bat`. This will install the following components:
|
||||
|
||||
* [Git for Windows](https://github.com/microsoft/git) (with custom patches)
|
||||
* Scalar
|
||||
* [Watchman](https://github.com/facebook/watchman), if you use the `--watchman` argument.
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* [Getting Started](getting-started.md): Get started with Scalar.
|
||||
Includes `scalar register`, `scalar unregister`, `scalar clone`, and
|
||||
`scalar delete`.
|
||||
|
||||
* [Advanced Features](advanced.md):
|
||||
For expert users who want full control of Scalar's activity. Includes
|
||||
`scalar run <task>`, `scalar pause`, `scalar resume`.
|
||||
|
||||
* [Troubleshooting](troubleshooting.md):
|
||||
Collect diagnostic information or update custom settings. Includes
|
||||
`scalar diagnose`, `scalar config`, `scalar upgrade`, and `scalar cache-server`.
|
||||
|
||||
* [The Philosophy of Scalar](philosophy.md): Why does Scalar work the way
|
||||
it does, and how do we make decisions about its future?
|
||||
|
||||
* [Frequently Asked Questions](faq.md)
|
||||
Scalar: Enabling Git at Scale
|
||||
=============================
|
||||
|
||||
Scalar is a tool that helps Git scale to some of the largest Git repositories.
|
||||
It achieves this by enabling some advanced Git features, such as:
|
||||
|
||||
* *Sparse-checkout:* limits the size of your working directory.
|
||||
|
||||
* *File system monitor:* tracks the recently modified files and eliminates
|
||||
the need for Git to scan the entire worktree.
|
||||
|
||||
* *Commit-graph:* accelerates commit walks and reachability calculations,
|
||||
speeding up commands like `git log`.
|
||||
|
||||
* *Multi-pack-index:* enables fast object lookups across many pack-files.
|
||||
|
||||
* *Incremental repack:* Repacks the packed Git data into fewer pack-file
|
||||
without disrupting concurrent commands by using the multi-pack-index.
|
||||
|
||||
By running `scalar register` in any Git repo, Scalar will automatically enable
|
||||
these features for that repo and start running suggested maintenance in the
|
||||
background.
|
||||
|
||||
Repos cloned with the `scalar clone` command use the
|
||||
[GVFS protocol](https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md)
|
||||
to significantly reduce the amount of data required to get started
|
||||
using a repository. By delaying all blob downloads until they are required,
|
||||
Scalar allows you to work with very large repositories quickly. This protocol
|
||||
allows a network of _cache servers_ to serve objects with lower latency and
|
||||
higher throughput. The cache servers also reduce load on the central server.
|
||||
|
||||
Installing on macOS
|
||||
------------------
|
||||
|
||||
To install Scalar on macOS,
|
||||
[download the `Installers_macOS_Release.zip` from the releases page](https://github.com/microsoft/scalar/releases).
|
||||
Extract the `Installers_macOS_Release` folder, `cd` into it, and run `./InstallScalar.sh` in a Terminal window.
|
||||
The script may prompt for your password as it installs the following components:
|
||||
|
||||
* [Git](https://github.com/microsoft/git) (with custom patches)
|
||||
* [Git Credential Manager Core](https://github.com/microsoft/Git-Credential-Manager-Core)
|
||||
* Scalar
|
||||
* [Watchman](https://github.com/facebook/watchman), unless you use the `--no-watchman` argument.
|
||||
|
||||
Installing on Windows
|
||||
--------------------
|
||||
|
||||
To install Scalar on Windows,
|
||||
[download the `Installers_Windows_Release.zip` from the releases page](https://github.com/microsoft/scalar/releases).
|
||||
Extract the `Installers_Windows_Release` folder, open it in a command prompt, and
|
||||
run `InstallScalar.bat`. This will install the following components:
|
||||
|
||||
* [Git for Windows](https://github.com/microsoft/git) (with custom patches)
|
||||
* Scalar
|
||||
* [Watchman](https://github.com/facebook/watchman), if you use the `--watchman` argument.
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* [Getting Started](getting-started.md): Get started with Scalar.
|
||||
Includes `scalar register`, `scalar unregister`, `scalar clone`, and
|
||||
`scalar delete`.
|
||||
|
||||
* [Advanced Features](advanced.md):
|
||||
For expert users who want full control of Scalar's activity. Includes
|
||||
`scalar run <task>`, `scalar pause`, `scalar resume`.
|
||||
|
||||
* [Troubleshooting](troubleshooting.md):
|
||||
Collect diagnostic information or update custom settings. Includes
|
||||
`scalar diagnose`, `scalar config`, `scalar upgrade`, and `scalar cache-server`.
|
||||
|
||||
* [The Philosophy of Scalar](philosophy.md): Why does Scalar work the way
|
||||
it does, and how do we make decisions about its future?
|
||||
|
||||
* [Frequently Asked Questions](faq.md)
|
||||
|
|
|
@ -1,65 +1,65 @@
|
|||
The Philosophy of Scalar
|
||||
========================
|
||||
|
||||
The team building Scalar has **opinions** about Git performance. Scalar
|
||||
takes out the guesswork by automatically configuring your Git repositories
|
||||
to take advantage of the latest and greatest features. It is difficult to
|
||||
say that these are the absolute best settings for every repository, but
|
||||
these settings do work for some of the largest repositories in the world.
|
||||
|
||||
Scalar intends to do very little more than the standard Git client. We
|
||||
actively implement new features into Git instead of Scalar, then update
|
||||
Scalar only to configure those new settings. In particular, we are porting
|
||||
features like background maintenance to Git to make Scalar simpler and
|
||||
make Git more powerful.
|
||||
|
||||
Scalar ships with [a custom version of Git][microsoft-git],
|
||||
but performs most of its benefits without that version. The only feature
|
||||
that is not intended to ever reach the standard Git client is Scalar's use
|
||||
of [the GVFS Protocol][gvfs-protocol].
|
||||
The GVFS Protocol is a way to reduce object transfer between client and
|
||||
server, named for its use in [VFS for Git](https://github.com/microsoft/vfsforgit).
|
||||
|
||||
If you don't use the GVFS Protocol, then most of the value of Scalar can
|
||||
be found in the core Git client. However, most of the advanced features
|
||||
that really optimize Git's performance are off by default for compatibility
|
||||
reasons. To really take advantage of Git's latest and greatest features,
|
||||
you either need to study the [`git config` documentation](https://git-scm.com/docs/git-config)
|
||||
and regularly read [the Git release notes](https://github.com/git/git/tree/master/Documentation/RelNotes).
|
||||
Even if you do all that work and customize your Git settings on your machines,
|
||||
you likely will want to share those settings with other team members.
|
||||
Or, you can just use Scalar!
|
||||
|
||||
Using `scalar register` on an existing Git repository will give you these
|
||||
benefits:
|
||||
|
||||
* Additional compression of your `.git/index` file.
|
||||
* Hourly background `git fetch` operations, keeping you in-sync with your
|
||||
remotes.
|
||||
* Advanced data structures, such as the `commit-graph` and `multi-pack-index`
|
||||
are updated automatically in the background.
|
||||
* If Watchman is installed, then the FileSystem Monitor hook is configured
|
||||
to use Watchman's change-tracking, providing faster commands such as
|
||||
`git status` or `git add`.
|
||||
|
||||
Additionally, if you use `scalar clone` to create a new repository, then
|
||||
you will automatically get these benefits:
|
||||
|
||||
* Use Git's partial clone feature to only download the files you need for
|
||||
your current checkout.
|
||||
* Use Git's [sparse-checkout feature][sparse-checkout] to minimize the
|
||||
number of files required in your working directory.
|
||||
[Read more about sparse-checkout here.][sparse-checkout-blog]
|
||||
* Create the Git repository inside `<repo-name>/src` to make it easy to
|
||||
place build artifacts outside of the Git repository, such as in
|
||||
`<repo-name>/bin` or `<repo-name>/packages`.
|
||||
|
||||
We also admit that these **opinions** can always be improved! If you have
|
||||
an idea of how to improve our setup, consider [creating an issue](https://github.com/microsoft/scalar/issues/new) or contributing a pull request! Some [existing](https://github.com/microsoft/scalar/issues/382)
|
||||
[issues](https://github.com/microsoft/scalar/issues/388) have already
|
||||
improved our configuration settings and roadmap!
|
||||
|
||||
[gvfs-protocol]: https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md
|
||||
[microsoft-git]: https://github.com/microsoft/git
|
||||
[sparse-checkout]: https://git-scm.com/docs/git-sparse-checkout
|
||||
[sparse-checkout-blog]: https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/
|
||||
The Philosophy of Scalar
|
||||
========================
|
||||
|
||||
The team building Scalar has **opinions** about Git performance. Scalar
|
||||
takes out the guesswork by automatically configuring your Git repositories
|
||||
to take advantage of the latest and greatest features. It is difficult to
|
||||
say that these are the absolute best settings for every repository, but
|
||||
these settings do work for some of the largest repositories in the world.
|
||||
|
||||
Scalar intends to do very little more than the standard Git client. We
|
||||
actively implement new features into Git instead of Scalar, then update
|
||||
Scalar only to configure those new settings. In particular, we are porting
|
||||
features like background maintenance to Git to make Scalar simpler and
|
||||
make Git more powerful.
|
||||
|
||||
Scalar ships with [a custom version of Git][microsoft-git],
|
||||
but performs most of its benefits without that version. The only feature
|
||||
that is not intended to ever reach the standard Git client is Scalar's use
|
||||
of [the GVFS Protocol][gvfs-protocol].
|
||||
The GVFS Protocol is a way to reduce object transfer between client and
|
||||
server, named for its use in [VFS for Git](https://github.com/microsoft/vfsforgit).
|
||||
|
||||
If you don't use the GVFS Protocol, then most of the value of Scalar can
|
||||
be found in the core Git client. However, most of the advanced features
|
||||
that really optimize Git's performance are off by default for compatibility
|
||||
reasons. To really take advantage of Git's latest and greatest features,
|
||||
you either need to study the [`git config` documentation](https://git-scm.com/docs/git-config)
|
||||
and regularly read [the Git release notes](https://github.com/git/git/tree/master/Documentation/RelNotes).
|
||||
Even if you do all that work and customize your Git settings on your machines,
|
||||
you likely will want to share those settings with other team members.
|
||||
Or, you can just use Scalar!
|
||||
|
||||
Using `scalar register` on an existing Git repository will give you these
|
||||
benefits:
|
||||
|
||||
* Additional compression of your `.git/index` file.
|
||||
* Hourly background `git fetch` operations, keeping you in-sync with your
|
||||
remotes.
|
||||
* Advanced data structures, such as the `commit-graph` and `multi-pack-index`
|
||||
are updated automatically in the background.
|
||||
* If Watchman is installed, then the FileSystem Monitor hook is configured
|
||||
to use Watchman's change-tracking, providing faster commands such as
|
||||
`git status` or `git add`.
|
||||
|
||||
Additionally, if you use `scalar clone` to create a new repository, then
|
||||
you will automatically get these benefits:
|
||||
|
||||
* Use Git's partial clone feature to only download the files you need for
|
||||
your current checkout.
|
||||
* Use Git's [sparse-checkout feature][sparse-checkout] to minimize the
|
||||
number of files required in your working directory.
|
||||
[Read more about sparse-checkout here.][sparse-checkout-blog]
|
||||
* Create the Git repository inside `<repo-name>/src` to make it easy to
|
||||
place build artifacts outside of the Git repository, such as in
|
||||
`<repo-name>/bin` or `<repo-name>/packages`.
|
||||
|
||||
We also admit that these **opinions** can always be improved! If you have
|
||||
an idea of how to improve our setup, consider [creating an issue](https://github.com/microsoft/scalar/issues/new) or contributing a pull request! Some [existing](https://github.com/microsoft/scalar/issues/382)
|
||||
[issues](https://github.com/microsoft/scalar/issues/388) have already
|
||||
improved our configuration settings and roadmap!
|
||||
|
||||
[gvfs-protocol]: https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md
|
||||
[microsoft-git]: https://github.com/microsoft/git
|
||||
[sparse-checkout]: https://git-scm.com/docs/git-sparse-checkout
|
||||
[sparse-checkout-blog]: https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
Troubleshooting
|
||||
===============
|
||||
|
||||
Upgrade
|
||||
-------
|
||||
|
||||
The Scalar service checks for new versions of Scalar daily and will prompt you
|
||||
for upgrade using a notification. To check yourself, run `scalar upgrade` to
|
||||
see if an upgrade is available. Run `scalar upgrade --confirm` to actually
|
||||
perform the upgrade, if you wish.
|
||||
|
||||
Diagnosing Issues
|
||||
-----------------
|
||||
|
||||
The `scalar diagnose` command collects logs and config details for the current
|
||||
repository. The resulting zip file helps root-cause issues.
|
||||
|
||||
When run inside your repository, creates a zip file containing several important
|
||||
files for that repository. This includes:
|
||||
|
||||
* All log files from `scalar` commands run in the enlistment, including
|
||||
maintenance steps.
|
||||
|
||||
* Log files from the Scalar service.
|
||||
|
||||
* Configuration files from your `.git` folder, such as the `config` file,
|
||||
`index`, `hooks`, and `refs`.
|
||||
|
||||
* A summary of your Git object database, including the number of loose objects
|
||||
and the names and sizes of pack-files.
|
||||
|
||||
As the `diagnose` command completes, it provides the path of the resulting
|
||||
zip file. This zip can be sent to the support team for investigation.
|
||||
|
||||
Modifying Configuration Values
|
||||
------------------------------
|
||||
|
||||
The Scalar-specific configuration is only available for repos using the
|
||||
GVFS protocol.
|
||||
|
||||
### Cache Server URL
|
||||
|
||||
When using an enlistment cloned with `scalar clone` and the GVFS protocol,
|
||||
you will have a value called the cache server URL. Cache servers are a feature
|
||||
of the GVFS protocol to provide low-latency access to the on-demand object
|
||||
requests. This modifies the `gvfs.cache-server` setting in your local Git config
|
||||
file.
|
||||
|
||||
Run `scalar cache-server --get` to see the current cache server.
|
||||
|
||||
Run `scalar cache-server --list` to see the available cache server URLs.
|
||||
|
||||
Run `scalar cache-server --set=<url>` to set your cache server to `<url>`.
|
||||
|
||||
### Scalar Config
|
||||
|
||||
The `scalar config` command is used for customizing the feed used for
|
||||
Scalar upgrades. This is so large teams can bundle a custom installer
|
||||
or other tools along with Scalar upgrades.
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
Upgrade
|
||||
-------
|
||||
|
||||
The Scalar service checks for new versions of Scalar daily and will prompt you
|
||||
for upgrade using a notification. To check yourself, run `scalar upgrade` to
|
||||
see if an upgrade is available. Run `scalar upgrade --confirm` to actually
|
||||
perform the upgrade, if you wish.
|
||||
|
||||
Diagnosing Issues
|
||||
-----------------
|
||||
|
||||
The `scalar diagnose` command collects logs and config details for the current
|
||||
repository. The resulting zip file helps root-cause issues.
|
||||
|
||||
When run inside your repository, creates a zip file containing several important
|
||||
files for that repository. This includes:
|
||||
|
||||
* All log files from `scalar` commands run in the enlistment, including
|
||||
maintenance steps.
|
||||
|
||||
* Log files from the Scalar service.
|
||||
|
||||
* Configuration files from your `.git` folder, such as the `config` file,
|
||||
`index`, `hooks`, and `refs`.
|
||||
|
||||
* A summary of your Git object database, including the number of loose objects
|
||||
and the names and sizes of pack-files.
|
||||
|
||||
As the `diagnose` command completes, it provides the path of the resulting
|
||||
zip file. This zip can be sent to the support team for investigation.
|
||||
|
||||
Modifying Configuration Values
|
||||
------------------------------
|
||||
|
||||
The Scalar-specific configuration is only available for repos using the
|
||||
GVFS protocol.
|
||||
|
||||
### Cache Server URL
|
||||
|
||||
When using an enlistment cloned with `scalar clone` and the GVFS protocol,
|
||||
you will have a value called the cache server URL. Cache servers are a feature
|
||||
of the GVFS protocol to provide low-latency access to the on-demand object
|
||||
requests. This modifies the `gvfs.cache-server` setting in your local Git config
|
||||
file.
|
||||
|
||||
Run `scalar cache-server --get` to see the current cache server.
|
||||
|
||||
Run `scalar cache-server --list` to see the available cache server URLs.
|
||||
|
||||
Run `scalar cache-server --set=<url>` to set your cache server to `<url>`.
|
||||
|
||||
### Scalar Config
|
||||
|
||||
The `scalar config` command is used for customizing the feed used for
|
||||
Scalar upgrades. This is so large teams can bundle a custom installer
|
||||
or other tools along with Scalar upgrades.
|
||||
|
|
Загрузка…
Ссылка в новой задаче