Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cake support #932

Merged
merged 40 commits into from Oct 25, 2017
Merged

Cake support #932

merged 40 commits into from Oct 25, 2017

Conversation

bjorkstromm
Copy link
Member

@bjorkstromm bjorkstromm commented Aug 2, 2017

Opening PR to get feedback.

Omnisharp.Cake piggybacks on OmniSharp.Roslyn.CSharp services, but will intercept and handle buffer updates before sending them to C# services... This is how it works.

  1. We have this custom tool Bakery which is doing Cake script analysis and CodeGen
  2. When OmniSharp starts up, a bakery process is started and a communication channel is opened between omnisharp.exe and cake.bakery.exe
  3. Whenever a buffer update occurs for a *.cake file it is sent to the bakery process in order to get analysed and a Roslyn compatible script is returned.
  4. The roslyn compatible script is added to the buffer manager and so on....

All feedback is welcome! @david-driscoll @DustinCampbell @filipw

here is a small example project if you like to test it out. Please note that Cake.Bakery (which can be fetched from our MyGet feed) needs to be located in the workspace before starting OmniSharp. It should be located in the tools folder. E.g. ${workspaceRoot}/tools/ folder or any other folder specified in cake.config.

Will send accompanying PR in Omnisharp-VSCode repo soon.

TODO:

  • Don't hardcode Cake.Bakery.exe path to $(toolsdir)/Cake.Bakery/tools/Cake.Bakery.exe
  • Fix lineoffsets when loading nested .cake files
  • Add documentation provider when loading addins
  • Load downloaded addins added after server was started
  • Add Unit Tests
  • Add integration tests
  • Cleanup

@bjorkstromm
Copy link
Member Author

omnisharp-cake

Here's a small preview.

{
var name = Path.GetFileName(filePath);

var assembly = AssemblyLoader.LoadFrom(cakeScript.Host.AssemblyPath);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use IAssemblyLoader

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.3.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="2.3.1" />
<PackageReference Include="Cake.Scripting.Transport" Version="0.1.0-unstable0091" />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be changed to 0.1.0 once Bakery is finalized.

NuGet.Config Outdated
@@ -5,5 +5,6 @@
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
<add key="dotnet-cli" value="https://dotnet.myget.org/F/cli-deps/api/v3/index.json" />
<add key="cake-nightly" value="https://www.myget.org/F/cake/api/v3/index.json" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this feed permanent? I assume it not, but just checking. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not permanent. Only used until Cake.Scripting bits (alias bakery) is finalized and pushed to NuGet.

var configurationPath = Path.Combine(environment.TargetDirectory, "cake.config");
if (File.Exists(configurationPath))
{
var parser = new ConfigurationParser();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parser will throw if the config is found among other things, if this throws in the constructor that may be a very very bad thing when booting up MEF.

The parser should probably either not throw, or should we should catch specific exceptions that don't matter.

var value = tokens.Current.Value;
if (ContainsWhiteSpace(value))
{
throw new InvalidOperationException("Sections cannot contain whitespace.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does cake do in this scenario, does it throw if the config has invalid values or does it default those values?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration handling is "copy-pasted-with-pride" from the Cake repo. Now that I look at it, I should remove any exception throwing and just set sensible defaults.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A second set of 👀 always helps!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went the Catch-and-Log route instead. Makes more sense than silently continue and keeps code in sync with code in Cake.

@bjorkstromm
Copy link
Member Author

@filipw @david-driscoll sounds like a great idea!

@DustinCampbell
Copy link
Contributor

FWIW, Travis CI failed on Linux. It looks like a real test failure in the Cake unit tests.

Examples:

39;49m�[31m    OmniSharp.Cake.Tests.AutoCompleteFacts.ShouldGenerateFromHostObject [FAIL]
�[39;49m�[37m      System.NullReferenceException : Object reference not set to an instance of an object
�[39;49m�[30m      Stack Trace:
�[39;49m�[37m          at OmniSharp.Cake.Services.CakeScriptService.Generate (Cake.Scripting.Abstractions.Models.FileChange fileChange) [0x00001] in <c4e6a1d4b56f401e87edf025a609f888>:0 
�[39;49m�[37m          at OmniSharp.Cake.Services.RequestHandlers.Buffer.UpdateBufferHandler+<Handle>d__3.MoveNext () [0x0016f] in <c4e6a1d4b56f401e87edf025a609f888>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at OmniSharp.Cake.Tests.AutoCompleteFacts+<FindCompletionsAsync>d__5.MoveNext () [0x00273] in <a83d90541b74416a88991defa1662a99>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at OmniSharp.Cake.Tests.AutoCompleteFacts+<ShouldGenerateFromHostObject>d__4.MoveNext () [0x00072] in <a83d90541b74416a88991defa1662a99>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[31m    OmniSharp.Cake.Tests.LineIndexHelperFacts.TranslateToGenerated_Should_Translate_Index_In_Single_File(index: 0, expected: 8208) [FAIL]
�[39;49m�[37m      System.InvalidOperationException : Could not load manifest resource stream.
�[39;49m�[30m      Stack Trace:
�[39;49m�[37m          at OmniSharp.Cake.Tests.LineIndexHelperFacts.GetResourceContent (System.String resourceName) [0x00017] in <a83d90541b74416a88991defa1662a99>:0 
�[39;49m�[37m          at OmniSharp.Cake.Tests.LineIndexHelperFacts.GetGeneratedFileContent (System.String name) [0x00016] in <a83d90541b74416a88991defa1662a99>:0 
�[39;49m�[37m          at OmniSharp.Cake.Tests.LineIndexHelperFacts+<TranslateToGenerated_Should_Translate_Index_In_Single_File>d__12.MoveNext () [0x0001a] in <a83d90541b74416a88991defa1662a99>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m        --- End of stack trace from previous location where exception was thrown ---
�[39;49m�[37m          at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 
�[39;49m�[37m          at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in <c9f8153c41de4f8cbafd0e32f9bf6b28>:0 

@bjorkstromm
Copy link
Member Author

@DustinCampbell yes, it feels like some problem using cake.bakery.exe on Linux within the unit tests. Will try to spin up the old virtual machine and give it a go later tonight.

@bjorkstromm bjorkstromm changed the title [WIP] Cake support Cake support Oct 22, 2017
@bjorkstromm
Copy link
Member Author

@david-driscoll @filipw @DustinCampbell removed [WIP] tag now 😉

}
else
{
lineIndex = request.Line + 7;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these arbitrary offsets look scary 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is scary, but it has a simple explanation. As GotoDefinition would normally point to the generated DSL, we are instead rerouting to the original extension method (from which the DSL was generated). Ugly, but it works 😄 7 line offset for properties, 3 line offset for methods.

{
var document = solution.GetDocument(documentId);
var project = document.Project;
var compilationOptions = GetCompilationOptions(e.Usings);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is going to be very inefficient, why not just call compilationOptions.WithUsings()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good catch!

@DustinCampbell
Copy link
Contributor

I just took a look at the changes to launch cake.bakery.exe. Looks good to me!

@bjorkstromm
Copy link
Member Author

@DustinCampbell nice! I’ll just fix @filipw’s comments then. @david-driscoll do you have anything to add?

@david-driscoll
Copy link
Member

Nothing else from me.

@filipw
Copy link
Member

filipw commented Oct 24, 2017

Out of curiosity, why do some files have a header:

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

are they copied from somewhere?

@bjorkstromm
Copy link
Member Author

@filipw, yes. They are copied from Cake, which is licensed under MIT license. We didn’t want OmniSharp to take on a dependency on Cake.Core and therefore it’ copied. It should only be the configuration bits.

@DustinCampbell
Copy link
Contributor

Per the comment, shouldn't we include the MIT License in the folder with these files? I did the same thing for OmniSharp.DotNet.ProjectModel after copying all of the code over from the .NET CLI.

@bjorkstromm
Copy link
Member Author

Sure, I can do that!

@gep13
Copy link

gep13 commented Oct 25, 2017

Great work @mholo65!

Can't wait to get this merged in, and start to roll it out!

Copy link
Member

@filipw filipw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@filipw
Copy link
Member

filipw commented Oct 25, 2017

Since everyone signed off, I will merge it 🎉

@filipw filipw merged commit 329d28a into OmniSharp:master Oct 25, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants