Cake Intellisense in Visual Studio Code

2017/11/8にやっとCakeでIntellisenseが効くようになりました!公式ブログ記事を簡単に邦訳しましたので、以下に記載します。

Intellisense

もしかしたらもう気づいたかもしれませんが、CakeチームはVisual Studio CodeでCakeファイルを編集中にIntellisenseが効くよう開発をおこなってきました。今日、OmniSharpが私たちのプルリクエスト(#932および#1681)をmergeし、Cakeのサポートを含むC# extension for Visual Studio Codeのv1.13.0がリリースされたことをアナウンスすることができ、大変嬉しく思います。これに加え、私たちはbakeryという新しいツールをリリースしました。これはスクリプト解析/コード生成ツールエンジンであり、CakeのIntellisenseを可能にしています。bakeryのより詳細な情報や、バックグラウンドで何が起こっているのかについては、後日ブログで紹介します。

How

どうやってIntellisenseを有効化するのでしょうか?それでは以下の手順に従ってください(Visual Studio Codeは既にインストール済みであると仮定します)。

  1. Visual Studio Codeを起動し、Cakeファイルの存在するフォルダへ移動します。
  2. C# for Visual Studio Codeのv1.13.0がインストールされていることを確認します。
  3. Visual Studio Code Extension for Cakeのv0.10.1がインストールされていることを確認します。
  4. Caketoolsフォルダにインストールされていることを確認します。addinが2回インストールされることを避けるため、v0.22.0以降を推奨します。最も簡単な方法は、.\build.ps1を実行することです。
  5. Bakerytoolsフォルダにインストールされていることを確認します。最も簡単な方法は、Visual Studio Code Extension for CakeのInstall intellisense supportコマンドを実行することです。コマンドパレットを開いて「cake」と入力し、当該オプションを選択してください。
  6. ここで、Visual Studio Code上で当該フォルダを閉じ、再び開く必要があります。
  7. Success! f:id:Intestine:20171112230349p:plain

Troubleshooting

Q: 上記手順を実行しましたが、Intellisenseが有効になりません。

C# Extension for Visual Studio Codeは、全ての*.slnファイルを検知し、omnisharp起動時にそのディレクトリを対象とします。もし*.cakeファイルが異なる階層に配置されていた場合、project selectorCakeプロジェクトを選択する必要があります。

Q: Cakeプロジェクトを選択しましたが、Intellisenseが有効になりません。

OmniSharp Logにエラーや警告が表示されていないかどうか確認してください。

[warn]: OmniSharp.Cake.CakeProjectSystem
    Cake script service not connected. Aborting.

上記のログは、Cake.Bakerytoolsフォルダにインストールされていないことを示しています。それに対して、以下のログは大抵の場合、Caketoolsフォルダにインストールされていないことを示しています(よりよいエラーメッセージに向けて修正中です)。

[fail]: OmniSharp.Cake.CakeProjectSystem
    c:\Users\mb\src\gh\bakery\setup.cake will be ignored due to an following error
    System.TypeLoadException: A null or zero length string does not represent a valid Type.

Q: エラーメッセージは表示されていませんが、それでもIntellisenseが有効になりません。

OmniSharp Logを表示し、Cakeに関係する箇所を探してください。もし適切にセットアップされていれば、少なくとも以下のようなログが表示されているはずです。

[info]: OmniSharp.Cake.CakeProjectSystem
    Detecting Cake files in 'c:\Users\mb\src\gh\bakery'.
[info]: OmniSharp.Cake.CakeProjectSystem
    Found 29 Cake files.

表示されていない場合、C#拡張機能v1.13.0のインストール時に問題が発生した可能性があります。拡張機能を一度アンインストールし、その後再度インストールしてみてください。その後、Windowsの場合は%userprofile%\.vscode\extensions\ms-vscode.csharp-1.13.0\.omnisharp\LinuxないしmacOSの場合は~/.vscode/extensions/ms-vscode.csharp-1.13.0/.omnisharp/を開き、OmniSharp.Cake.dllが存在することを確認してください。

Q: Intellisenseが有効になりましたが、その後追加したファイルが表示されません。

これはomnisharpの既知の問題であり、*.csxでも同様です。omnisharpチームとともに今後のリリースで改善されるよう取り組んでいます。

Q: Cake.CoreCLRtoolsフォルダにインストールされていればそれで充分でしょうか。

いいえ、現時点ではCake.CoreCLRではIntellisenseが有効になりません。

Q: 上記全てを試しましたが、まだIntellisenseが有効になりません。

Github上でbakeryリポジトリにissueを立てるか、Gitterで私たちにコンタクトをとってみてください。

Cake-Intellisence beta

※2017/11/07
C# Extension v1.13.0 beta5がリリースされたので、該当箇所を更新しました。

最近よく使っているCake。そろそろIntelliSenseが効くようになりそうです!
Visual Studio CodeのC# Extension v1.13.0からサポートされる予定ですが、現在beta5で動作確認できます。
以下、簡単な検証方法です(くれぐれも自己責任で!)。

Cake IntelliSence検証手順

  1. Visual Studio CodeのC#拡張を既にインストールしている場合はアンインストール。
  2. ここからcsharp-1.13.0-beta5.vsixをダウンロード。
  3. ダウンロードしたVSIXをインストール。
  4. Cake Extensionをインストールしていない場合はインストール。
  5. F1 → Cake: Install intellisence support
    /toolsディレクトリにCake.Bakeryがダウンロードされます。
    f:id:Intestine:20171103235243p:plain
    f:id:Intestine:20171103235235p:plain
  6. 対象の.cakeファイルを開き、Omnisharpと.NET Core Debuggerがインストールされるのを確認。
    f:id:Intestine:20171103235247p:plain
  7. 右下のSwitch projectsを選択。
    f:id:Intestine:20171103235306p:plain
  8. Cakeを選択。
    f:id:Intestine:20171103235303p:plain
  9. こんな感じでIntelliSenseが効くようになっているはず!
    f:id:Intestine:20171103235256p:plainf:id:Intestine:20171103235257p:plainf:id:Intestine:20171103235300p:plain

F12も使えます。 f:id:Intestine:20171103235229p:plain

いやーリリースが待ち遠しい!

Cakeビルド時エラー:Unknown token (2)

去年、Cakeビルド時のエラーについて触れました。

ビルド対象のプロジェクトのパスにマルチバイト文字が含まれているとエラーになります。 0.15.2まではうまくいってたんだけど、0.16.0からエラーになるみたい。

その後ソースを確認してみたところ、どうもTool(NuGet)を.cakeファイル内で読み込もうとすると、Globbingの際に一文字ずつこんな条件を満たすかどうかチェックしてるっぽい。

new Regex("^[0-9a-zA-Z\\+&%!@(). _-]$", RegexOptions.Compiled).IsMatch(character.ToString())

パスに使えない文字だけをホワイトリスト方式で検出するようにPR送ってもいいけど、対策見つけたんでちょっと保留。

対策

.cakeファイル内に#tool nuget:?package=NUnit.ConsoleRunner&version=3.4.0と書いてNuGetパッケージを読み込むのではなく、toolsディレクトリ内にpackages.configを置いてこんな感じに書いておく。

<?xml version="1.0" encoding="utf-8"?>
<packages>
    <package id="Cake" version="0.19.3" />
    <package id="NUnit.ConsoleRunner" version="3.4.0" />
</packages>

そうすると、bootstrapperを走らせた時にNuGetパッケージも復元してくれるので、パスにマルチバイト文字が含まれていてもビルド時にエラーにはならない(参考)。
マルチバイト文字なんか使わないのが一番なんだけど、リポジトリの都合上仕方がない場面もあるかと思います。そんな時は、bootstrapperでNuGet復元するようにしましょう。

ODP.NET Support for .NET Core

少し前になりますが、Oracle .NET Teamが、.NET Coreに対するODP.NETのサポートについてtweetしていました。

概要 (ODP.NET Managed Driver)

  • .NET Core : 2017年末にサポート (.NET Core 2.0以降)
  • ASP.NET Core : 未定 (.NET Coreに対するサポート開始以降)
  • Entity Framework Core : 未定 (.NET Coreに対するサポート開始以降)

以下、このgeneral product directionの主要な箇所を簡単に意訳してみました。


ODP.NET Statement of Direction for Microsoft .NET Core

Oracleは2017年の末頃に、.NET Coreに対するODP.NET Managed Driverを提供します。対象OSはWindowsおよびOracle Linuxの予定です。ODP.NET Managed Driverは他のOSに対するサポートを追加するかもしれません。他のLinuxディストリビューションに対してもサポートを継続して検討し、将来的には対象のリストに追加する予定です。

.NET Core 2.0よりも前のバージョンに対してODP.NETを提供する予定はありません。.NET Core 2.0において大幅に拡張されるAPIによって、ODP.NETによる.NET Coreのサポートが可能になります。

ODP.NETの最初のリリースにおいては、Entity Framework CoreおよびASP.NET Coreに対するサポートは想定していません。将来的にはこれらのフレームワークに対するサポートを提供する予定です。

.NET Coreに対するODP.NET Unmanaged Driverの提供は予定していません。


うーん、.NET Core 2.0のリリースが延びてるから、それにつられてOracleのproviderもずるずると…って感じですね。オープンソースにする予定はないって言ってるし。
Entity Framework Coreに対するproviderの開発に時間がかかるからリリースずらすっていうのはわかるけど。

Cake - C# Make -

Cakeって何?

Cakeを一言で言うと、「C#で書ける.NETのためのビルド自動化ツール」です。
定義は以下。

Cake (C# Make) is a cross platform build automation system with a C# DSL to do things like compiling code, copy files/folders, running unit tests, compress files and build NuGet packages.DSL

NuGetパッケージをリストア → ビルド → 単体テストカバレッジ取得 → パッケージング → NuGetリポジトリにPublish…みたいな一連の処理を全てC#で記述可能です。

Fullの.NET Frameworkと.NET Coreのどちらもビルドでき(MSBuild ToolsVersion 15.0は今対応中)、Cake自体の実装も昨年.NET Coreに移行しました。

Cakeの特徴

1. オープンソース
2016年6月に.NET Foundationに参加を表明しました。→.NET Foundation - Free as in Cake
現在、GitHub上で精力的に開発・管理されています。いきなりissueやPullRequest投げるよりも、まずgitterで質問してみるのがオススメ。

2. クロスプラットフォーム
WindowsLinuxおよびOS Xのいずれにおいても動作します。AppVeyor、Jenkins、VSTSTravisおよびBamboo等のCIツールにも対応済です。

3. ビルドスクリプトC#で書ける
皆さんは一連のビルド処理どうやってます?powershellやバッチファイルの秘伝のタレ…Fakeも有名ですが、F#なので敬遠してるって方も多いんじゃないかなあ。
CakeはFakeにかなり影響を受けていて、Taskベースのビルド処理を全てC#で記述できます。
実際のスクリプトはこんな感じ。

ふだんC#で開発している人ならば、そんなに違和感なくスラスラと読めるはず。

4. 拡張可能
プラットフォーム依存の処理を書きたい場合はAddinを開発することで拡張することができます(これもC#で書ける!)。Cakeスクリプトは基本的にC#でできることなら何でも書けるので、スクリプトごとにメソッドを書いてもいいですが、複数のアプリで使いまわしたい場合やCakeにContributeしたい場合はAddinを書くのがオススメ。
現在公開されているAddinは、AzureやAWS、Xamarin、Dockerなど80種以上。一覧はCake - Addinsを参照。

まとめ

.NET Foundationに参加したあたりに試しに使ってみたら結構すんなり適用できたので、最近はもっぱらCakeで遊んでます。有名どころだとNUnitなんかでも採用されてたりするし、Communityの雰囲気もいいんでしばらくは期待できそう。.NET Coreでの使用例についても書きたいけど、Visual Studio2017がRTMになってからですね。

Cakeビルド時エラー:Unknown token (1)

Unknown token

最近C#/ASP.NETアプリのビルドにCakeを使うことが多くなったのですが、久しぶりにはまってしまったのでメモ。

ビルド対象のプロジェクトのパスにマルチバイト文字が含まれているとエラーになります。 0.15.2まではうまくいってたんだけど、0.16.0からエラーになるみたい。 普段日本語のプロジェクト名なんてほとんど使わないから気が付かなかった…

再現手順

こんな感じで適当なサンプルをcloneしてきて…

mkdir C:\マルチバイト
cd C:\マルチバイト
git clone https://github.com/cake-build/example
cd example

Verbosity=Diagnosticでビルドしてみると、こんなエラーを吐きます。

PS C:\マルチバイト\example> .\build.ps1
Preparing to run build script...
Running build script...
Module directory does not exist.
Analyzing build script...
Analyzing C:/マルチバイト/example/build.cake...
Processing build script...
Installing tools...
Error: System.NotSupportedException: Unknown token
   場所 Cake.Core.IO.Globbing.GlobTokenizer.ScanToken()
   場所 Cake.Core.IO.Globbing.GlobTokenizer.Scan()
   場所 Cake.Core.IO.Globbing.GlobParserContext.Accept()
   場所 Cake.Core.IO.Globbing.GlobParser.Parse(GlobParserContext context)
   場所 Cake.Core.IO.Globbing.GlobParser.Parse(String pattern, Boolean caseSensitive)
   場所 Cake.Core.IO.Globber.Match(String pattern, Func`2 predicate)
   場所 Cake.Core.IO.GlobberExtensions.Match(IGlobber globber, String pattern)
   場所 Cake.Core.IO.GlobberExtensions.GetFiles(IGlobber globber, String pattern)
   場所 Cake.NuGet.NuGetContentResolver.GetFiles(DirectoryPath path, PackageReference package)
   場所 Cake.NuGet.NuGetContentResolver.GetToolFiles(DirectoryPath path, PackageReference package)
   場所 Cake.NuGet.NuGetContentResolver.GetFiles(DirectoryPath path, PackageReference package, PackageType type)
   場所 Cake.NuGet.NuGetPackageInstaller.Install(PackageReference package, PackageType type, DirectoryPath path)
   場所 Cake.Core.Scripting.ScriptProcessor.InstallTools(ScriptAnalyzerResult analyzerResult, DirectoryPath installPath)

   場所 Cake.Core.Scripting.ScriptRunner.Run(IScriptHost host, FilePath scriptPath, IDictionary`2 arguments)
   場所 Cake.Commands.BuildCommand.Execute(CakeOptions options)
   場所 Cake.CakeApplication.Run(CakeOptions options)
   場所 Cake.Program.Main()

なぜ?

どーやらCake.Core.IO.Globbing.GlobTokenizer.ScanToken()でthrow new NotSupportedExceptionされてるみたいなんだけど、なんでだろ? Commit履歴見てみると、ちょくちょくパスに使える文字を追加してる…ホワイトリストじゃなくて禁止文字だけ定義したブラックリスト方式でいいんじゃない?

gitterで聞いてみたところ、gep13に「issueあげてくれますか?」って言われたんで書いてみた→#1422
まあこの手のマルチバイト問題はよくあることですよね。まだCakeのソースは詳しく読んでないんで、年越しちゃうかな。

RTX810初期化

RTX810のフィルターをいじってたら、ミスってLANから外に出られなくなった…一度設定を整理するいいチャンスだと思い(こじつけ)、初期化した。 初期化方法は、前面の3つのボタンを押したまま、後ろの電源ボタンで電源を落とし、再起動。 しかしこれが非常に押しづらい。片手じゃ前面のボタン全て押せねーよ。 簡単にリセットされちゃ困るのはわかるんだけどね。RT58iにはリセットボタンがあったっけ。