Skip to content

Commit

Permalink
Merge branch 'master' into feature/watch-file-extension
Browse files Browse the repository at this point in the history
  • Loading branch information
filipw authored Dec 12, 2017
2 parents a54c6dd + cb42989 commit 7eb6366
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 53 deletions.
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,8 @@ after_deploy: |
git push origin $BRANCH_NAME
curl -X POST -H 'Authorization: token '$GITHUB_API_TOKEN'' -d '{ "title": "Upgrade to OmniSharp/omnisharp-roslyn '$TRAVIS_TAG'", "body": "*Automated PR* - Upgrade omnisharp-roslyn to '$TRAVIS_TAG'. [release patch]", "head": "'$BRANCH_NAME'", "base": "master" }' https://api.github.com/repos/OmniSharp/omnisharp-node-client/pulls
fi
# Only decrypt blob storage key for commits to master
if [ "$TRAVIS_PULL_REQUEST_BRANCH" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]
openssl aes-256-cbc -K $encrypted_89dcd8324ec1_key -iv $encrypted_89dcd8324ec1_i -in blobstring.txt.enc -out blobstring.txt -d
fi
Binary file added blobstring.txt.enc
Binary file not shown.
2 changes: 1 addition & 1 deletion src/OmniSharp.Abstractions/Services/IAssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface IAssemblyLoader

IReadOnlyList<Assembly> LoadAllFrom(string folderPath);

Assembly LoadFrom(string assemblyPath);
Assembly LoadFrom(string assemblyPath, bool dontLockAssemblyOnDisk = false);
}

public static class IAssemblyLoaderExtensions
Expand Down
7 changes: 7 additions & 0 deletions src/OmniSharp.Cake/CakeOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OmniSharp.Cake
{
public sealed class CakeOptions
{
public string BakeryPath { get; set; }
}
}
63 changes: 49 additions & 14 deletions src/OmniSharp.Cake/CakeProjectSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using OmniSharp.Cake.Services;
using OmniSharp.Helpers;
using OmniSharp.Models.WorkspaceInformation;
using OmniSharp.Roslyn.Utilities;
using OmniSharp.Services;

namespace OmniSharp.Cake
Expand All @@ -23,26 +24,31 @@ namespace OmniSharp.Cake
public class CakeProjectSystem : IProjectSystem
{
private readonly OmniSharpWorkspace _workspace;
private readonly MetadataFileReferenceCache _metadataReferenceCache;
private readonly IOmniSharpEnvironment _environment;
private readonly IAssemblyLoader _assemblyLoader;
private readonly ICakeScriptService _scriptService;
private readonly ILogger<CakeProjectSystem> _logger;
private readonly Dictionary<string, ProjectInfo> _projects;
private readonly Lazy<CSharpCompilationOptions> _compilationOptions;

private CakeOptions _options;

public string Key => "Cake";
public string Language => Constants.LanguageNames.Cake;
public IEnumerable<string> Extensions => new[] { ".cake" };

[ImportingConstructor]
public CakeProjectSystem(
OmniSharpWorkspace workspace,
MetadataFileReferenceCache metadataReferenceCache,
IOmniSharpEnvironment environment,
IAssemblyLoader assemblyLoader,
ICakeScriptService scriptService,
ILoggerFactory loggerFactory)
{
_workspace = workspace ?? throw new ArgumentNullException(nameof(workspace));
_metadataReferenceCache = metadataReferenceCache ?? throw new ArgumentNullException(nameof(metadataReferenceCache));
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
_assemblyLoader = assemblyLoader ?? throw new ArgumentNullException(nameof(assemblyLoader));
_scriptService = scriptService ?? throw new ArgumentNullException(nameof(scriptService));
Expand All @@ -54,6 +60,9 @@ public CakeProjectSystem(

public void Initalize(IConfiguration configuration)
{
_options = new CakeOptions();
configuration.Bind(_options);

_logger.LogInformation($"Detecting Cake files in '{_environment.TargetDirectory}'.");

// Nothing to do if there are no Cake files
Expand All @@ -66,10 +75,10 @@ public void Initalize(IConfiguration configuration)

_logger.LogInformation($"Found {allCakeFiles.Length} Cake files.");

// Check that script service is connected
if (!_scriptService.IsConnected)
// Try intialize Cake scripting service
if (!_scriptService.Initialize(_options))
{
_logger.LogWarning("Cake script service not connected. Aborting.");
_logger.LogWarning("Could not initialize Cake script service. Aborting.");
return;
}

Expand All @@ -82,6 +91,7 @@ public void Initalize(IConfiguration configuration)
FileName = cakePath,
FromDisk = true
});

var project = GetProject(cakeScript, cakePath);

// add Cake project to workspace
Expand Down Expand Up @@ -148,15 +158,27 @@ private void ScriptReferencesChanged(object sender, ReferencesChangedEventArgs e
var document = solution.GetDocument(documentId);
var project = document.Project;

var metadataReferences = e.References.Select(reference => MetadataReference.CreateFromFile(reference, documentation: GetDocumentationProvider(reference)));
var fileReferencesToRemove = project.MetadataReferences;
var metadataReferences = GetMetadataReferences(e.References);
var referencesToRemove = new HashSet<MetadataReference>(project.MetadataReferences, MetadataReferenceEqualityComparer.Instance);
var referencesToAdd = new HashSet<MetadataReference>(MetadataReferenceEqualityComparer.Instance);

foreach (var reference in metadataReferences)
{
if (referencesToRemove.Remove(reference))
{
continue;
}

if (referencesToAdd.Contains(reference))
{
continue;
}

_workspace.AddMetadataReference(project.Id, reference);
referencesToAdd.Add(reference);
}

foreach (var reference in fileReferencesToRemove)
foreach (var reference in referencesToRemove)
{
_workspace.RemoveMetadataReference(project.Id, reference);
}
Expand Down Expand Up @@ -205,8 +227,15 @@ private ProjectInfo GetProject(CakeScript cakeScript, string filePath)
{
var name = Path.GetFileName(filePath);

var assembly = _assemblyLoader.LoadFrom(cakeScript.Host.AssemblyPath);
var hostObjectType = Type.GetType(cakeScript.Host.TypeName, a => assembly, null, true);
if (!File.Exists(cakeScript.Host.AssemblyPath))
{
throw new FileNotFoundException($"Cake is not installed. Path {cakeScript.Host.AssemblyPath} does not exist.");
}
var hostObjectType = Type.GetType(cakeScript.Host.TypeName, a => _assemblyLoader.LoadFrom(cakeScript.Host.AssemblyPath, dontLockAssemblyOnDisk: true), null, false);
if (hostObjectType == null)
{
throw new InvalidOperationException($"Could not get host object type: {cakeScript.Host.TypeName}.");
}

return ProjectInfo.Create(
id: ProjectId.CreateNewId(Guid.NewGuid().ToString()),
Expand All @@ -217,18 +246,24 @@ private ProjectInfo GetProject(CakeScript cakeScript, string filePath)
language: LanguageNames.CSharp,
compilationOptions: cakeScript.Usings == null ? _compilationOptions.Value : _compilationOptions.Value.WithUsings(cakeScript.Usings),
parseOptions: new CSharpParseOptions(LanguageVersion.Default, DocumentationMode.Parse, SourceCodeKind.Script),
metadataReferences: cakeScript.References.Select(reference => MetadataReference.CreateFromFile(reference, documentation: GetDocumentationProvider(reference))),
metadataReferences: GetMetadataReferences(cakeScript.References),
// TODO: projectReferences?
isSubmission: true,
hostObjectType: hostObjectType);
}

private static DocumentationProvider GetDocumentationProvider(string assemblyPath)
private IEnumerable<MetadataReference> GetMetadataReferences(IEnumerable<string> references)
{
var assemblyDocumentationPath = Path.ChangeExtension(assemblyPath, ".xml");
return File.Exists(assemblyDocumentationPath)
? XmlDocumentationProvider.CreateFromFile(assemblyDocumentationPath)
: DocumentationProvider.Default;
foreach (var reference in references)
{
if (!File.Exists(reference))
{
_logger.LogWarning($"Unable to create MetadataReference. File {reference} does not exist.");
continue;
}

yield return _metadataReferenceCache.GetMetadataReference(reference);
}
}

private static CSharpCompilationOptions CreateCompilationOptions()
Expand Down
46 changes: 24 additions & 22 deletions src/OmniSharp.Cake/Services/CakeScriptService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Cake.Scripting.Abstractions;
using Cake.Scripting.Abstractions.Models;
using Cake.Scripting.Transport.Tcp.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using OmniSharp.Cake.Configuration;
using OmniSharp.Utilities;
Expand All @@ -16,42 +17,44 @@ namespace OmniSharp.Cake.Services
[Export(typeof(ICakeScriptService)), Shared]
public sealed class CakeScriptService : ICakeScriptService, IDisposable
{
private readonly ScriptGenerationClient _generationService;
private readonly IOmniSharpEnvironment _environment;
private readonly ICakeConfiguration _cakeConfiguration;
private readonly ILoggerFactory _loggerFactory;
private readonly IDictionary<string, ISet<string>> _cachedReferences;
private readonly IDictionary<string, ISet<string>> _cachedUsings;
private ScriptGenerationClient _generationService;

[ImportingConstructor]
public CakeScriptService(IOmniSharpEnvironment environment, ICakeConfiguration configuration, ILoggerFactory loggerFactory)
public CakeScriptService(IOmniSharpEnvironment environment, ICakeConfiguration cakeConfiguration, ILoggerFactory loggerFactory)
{
if (environment == null)
{
throw new ArgumentNullException(nameof(environment));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
_cakeConfiguration = cakeConfiguration ?? throw new ArgumentNullException(nameof(cakeConfiguration));
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_cachedReferences = new Dictionary<string, ISet<string>>();
_cachedUsings = new Dictionary<string, ISet<string>>();
}

var serverExecutablePath = ScriptGenerationToolResolver.GetExecutablePath(environment.TargetDirectory, configuration);
public bool Initialize(CakeOptions options)
{
var serverExecutablePath = ScriptGenerationToolResolver.GetExecutablePath(_environment.TargetDirectory, _cakeConfiguration, options);

if (File.Exists(serverExecutablePath))
{
_generationService = PlatformHelper.IsMono ?
new ScriptGenerationClient(new MonoScriptGenerationProcess(serverExecutablePath, environment, loggerFactory), environment.TargetDirectory, loggerFactory) :
new ScriptGenerationClient(serverExecutablePath, environment.TargetDirectory, loggerFactory);
new ScriptGenerationClient(new MonoScriptGenerationProcess(serverExecutablePath, _environment, _loggerFactory), _environment.TargetDirectory, _loggerFactory) :
new ScriptGenerationClient(serverExecutablePath, _environment.TargetDirectory, _loggerFactory);
}

IsConnected = _generationService != null;
_cachedReferences = new Dictionary<string, ISet<string>>();
_cachedUsings = new Dictionary<string, ISet<string>>();
return _generationService != null;
}

public CakeScript Generate(FileChange fileChange)
{
if (_generationService == null)
{
throw new InvalidOperationException("Service not initialized.");
}

var cakeScript = _generationService.Generate(fileChange);

// Set line processor for generated aliases. TODO: Move to Cake.Bakery
Expand All @@ -65,7 +68,7 @@ public CakeScript Generate(FileChange fileChange)
if (!cakeScript.References.SetEquals(references))
{
_cachedReferences[fileChange.FileName] = cakeScript.References;
OnReferencesChanged(new ReferencesChangedEventArgs(fileChange.FileName, cakeScript.References.ToList()));
OnReferencesChanged(new ReferencesChangedEventArgs(fileChange.FileName, cakeScript.References));
}

// Check if usings changed
Expand All @@ -82,7 +85,6 @@ public CakeScript Generate(FileChange fileChange)
return cakeScript;
}

public bool IsConnected { get; }
public event EventHandler<ReferencesChangedEventArgs> ReferencesChanged;
public event EventHandler<UsingsChangedEventArgs> UsingsChanged;

Expand Down
9 changes: 5 additions & 4 deletions src/OmniSharp.Cake/Services/ICakeScriptService.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
using Cake.Scripting.Abstractions;
using Microsoft.Extensions.Configuration;

namespace OmniSharp.Cake.Services
{
public interface ICakeScriptService : IScriptGenerationService
{
bool IsConnected { get; }
bool Initialize(CakeOptions options);

event EventHandler<ReferencesChangedEventArgs> ReferencesChanged;

Expand All @@ -30,11 +31,11 @@ protected ScriptChangedEventArgs(string scriptPath)

public class ReferencesChangedEventArgs : ScriptChangedEventArgs
{
public IReadOnlyCollection<string> References { get; }
public ISet<string> References { get; }

public ReferencesChangedEventArgs(string scriptPath, IReadOnlyCollection<string> references) : base(scriptPath)
public ReferencesChangedEventArgs(string scriptPath, ISet<string> references) : base(scriptPath)
{
References = references ?? new List<string>();
References = references ?? new HashSet<string>();
}
}

Expand Down
37 changes: 35 additions & 2 deletions src/OmniSharp.Cake/Services/ScriptGenerationToolResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,34 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using OmniSharp.Cake.Configuration;
using OmniSharp.Utilities;

namespace OmniSharp.Cake.Services
{
internal static class ScriptGenerationToolResolver
{
public static string GetExecutablePath(string rootPath, ICakeConfiguration configuration)
public static string GetExecutablePath(string rootPath, ICakeConfiguration configuration, CakeOptions options)
{
// First check if registered through OmniSharp options
var executablepath = options.BakeryPath;
if (!string.IsNullOrEmpty(executablepath) && File.Exists(executablepath))
{
return executablepath;
}

// First check if installed in workspace
executablepath = ResolveFromToolFolder(rootPath, configuration);
if (!string.IsNullOrEmpty(executablepath))
{
return executablepath;
}

// If not check from path
return ResolveFromPath();
}

private static string ResolveFromToolFolder(string rootPath, ICakeConfiguration configuration)
{
var toolPath = GetToolPath(rootPath, configuration);

Expand Down Expand Up @@ -54,5 +74,18 @@ private static IEnumerable<string> GetBakeryPaths(string toolPath)
}
}

private static string ResolveFromPath()
{
foreach (var searchPath in PlatformHelper.GetSearchPaths())
{
var path = Path.Combine(searchPath, "Cake.Bakery.exe");
if (File.Exists(path))
{
return path;
}
}

return string.Empty;
}
}
}
Loading

0 comments on commit 7eb6366

Please sign in to comment.