MPS 2019.2ヘルプ

マイグレーション

言語が公開され、ユーザーがそれを使い始めた後、言語の作者は言語定義へのさらなる変更に注意しなければなりません。特に、概念を削除したり、プロパティー、子、および概念への参照を追加および削除すると、前の言語バージョンと次の言語バージョンの間に互換性がなくなります。次の言語バージョンに更新すると、言語のユーザーに影響があります。自分のモデルが言語定義と一致しなくなり、適切なエラーがモデルから報告されるためです。

MPSはプロジェクトで使用されている言語のバージョンを追跡し、言語の使用箇所を最新のバージョンにアップグレードするための自動移行を提供します。言語設計者は、メンテナンス "移行"コードを作成してユーザーコードに対して自動的に実行し、言語定義に加えられた変更に準拠するようにユーザーコードを変更することができます。これは言語の移行と呼ばれます。

完全な言語の移行ストーリーには、いくつかの側面があります。

  • 言語設計者は、ユーザーコードを移行するためのスクリプトを作成し、言語とバンドルすることができます。

  • MPSはクライアントコードで使用されている言語バージョンを自動的に追跡する

  • MPSは、ユーザーのプロジェクトがすべての言語変更で最新であることを制御する

  • MPSは必要に応じて必要な移行を実行する

MPSでは、2種類の移行方法があります。

  • 言語の移行 - 次のバージョンの言語定義に準拠するようにプロジェクトをアップグレードするマイグレーション。各言語の移行は、言語定義のバージョンに関連付けられています。

  • プロジェクトのマイグレーション - これらは言語の使用箇所によって引き起こされるのではなく、代わりにそれら自身が実行されるべき条件を定義します。これらの移行は常にプロジェクト全体に適用されます。

言語バージョン

言語は、モジュール定義(.mpl)ファイルにバージョン番号を格納します。この数字は、言語の「マイグレーション」の側面で新しいマイグレーションが作成されたときに増加します。

言語を使用するモジュールには、モジュール(.msd、.mpl)ファイル内の使用されている各言語参照に関連付けられたバージョン番号が含まれています。これらはモジュールによって使用される言語バージョンを表します。このモジュールに対して対応する移行を実行して新しい言語バージョンに移行すると、番号が変わります。

言語のバージョン番号は、言語のプロパティーダイアログで手動で表示および変更できます。

Migrationx1003

利用可能な2つの番号があることに注意してください。

  • 言語バージョン - 言語の構造が変わるたびに更新されます

  • モジュールバージョン - モジュール内のノードへの参照が移行されるたびに更新されます。ノードの移動など、ソースを持つモジュールで移行を実行する場合は、移行が必要です。移行は参照または依存するモジュールで実行されます。モジュール・バージョンはそれを追跡します。

移行アシスタント

現在開いているプロジェクト内のモジュールが、現在存在しているものよりも古い言語のバージョンを参照していることをMPSが検出すると、移行アシスタントが実行されます。プロジェクトを最新バージョンの言語に更新するためにマイグレーションを実行するかどうかをユーザーにプロンプトします。

Migration1003

実行される移行の詳細リストがユーザーに提示されます。

Migration1

ユーザーが移行を開始すると、プロジェクトは完全に移行されます。移行を妨げる問題がある場合、移行されていないコードのリストとともに問題のリストがユーザーに提示されます。

言語の移行を定義する

言語定義のマイグレーションの側面では、マイグレーション移行クラスとして定義されています。移行クラスは、jetbrains.mps.lang.migration言語で定義されているMigrationScript概念のノードです。

Migration1001

言語の番号と移行

  • 各移行スクリプトの名前には番号が付いています

  • 各移行スクリプトはfrom versionプロパティーを定義する

新しい移行スクリプトが作成されると、言語バージョンが1増加し、移行のfromVersionフィールドがその言語バージョンの古い値に設定されます。作成された移行スクリプトは、古いバージョンから新しいバージョンへの移行を実行していると言えます。

言語の番号と移行のヒントとコツ

  • 移行を見逃すことはできません。言語にバージョンXとバージョンYからの移行が含まれている場合は、XとYの間の各バージョンの移行も含まれているはずです。一部のバージョンで移行が見つからない場合、これはバージョンXから移行できないことを意味します。そのような言語の生成はエラーで終わるでしょう。

  • 言語のすべての移行を保存する必要はありません。一部の言語が「公開」されていて、古い移行の一部を削除する必要がある場合は、削除することもできます。残りのマイグレーションのfromバージョンは、範囲A..Bを形成するはずです。ここで、Aは任意の古いバージョンで、B = <現在のバージョン> - 1です。

  • マイグレーションが誤って作成され、公開されていない(つまり、自分のプロジェクトで実行したユーザーがいない)場合は、自由に削除できます。移行を削除した後、言語のコンテキストメニューから言語のバージョンを修正を実行します - このアクションにより、言語のバージョンを最後の移行のバージョンと同期させることができます。これをするとき十分気をつける

Migration1002

移行のしくみ

Migrationx1002

マイグレーションによって提供される可能性があるいくつかのオプションの要素があります。

  • 実行後 - 移行スクリプト間に順序付けの制約を設ける

  • 注釈データを生成する - このスクリプトによって生成され、後の移行スクリプトによって消費される可能性がある移行データを保持するために使用されるコンセプト宣言を指定します。

  • 注釈データが必要 - 以前のマイグレーション・スクリプトによって生成されたマイグレーション・データを表すために使用されるコンセプト宣言を指定します。また、この移行スクリプト内でデータを表すための論理名をデータに付けます。

  • データを生成する (非推奨) - 移行データを転送する従来の変種は、ノード注釈の代わりに外部ファイルを使用します。

  • データが必要です (非推奨) - 移行データの転送の従来の変種。

  • description - スクリプトのわかりやすい説明文

  • executeメソッド - 各マイグレーションはexecute()メソッドを定義します。これはユーザーモデルの実際のモデル変換を実行します。この方法は、パラメータとしてユーザモジュールを受け取り、必要な注釈データセクション内の定義された要素を参照することができます。

データ本番と消費

移行スクリプト間でデータを渡す機能は、移行プロセス分割するのに役立ちます。たとえば、ある移行スクリプトは古い概念から新しい概念にノードを移行しますが、次の移行スクリプトは新しいノードを指すように元のノードへのすべての参照を移行します。これが機能するためには、最初のスクリプトは新旧のノードのIDを格納し、生成されたデータとしてマッピングを公開する必要があります。2番目の移行スクリプトは、必要なデータとしてデータを消費します。古いノードへの参照を更新する必要があるたびに、データは新しいノードのIDを見つけるために使用されます。技術的には、データを生成することは、データが関連する場所に十分近い任意のノードに、データを含む特別な属性を単に接続することです。注釈がモデル全体に関連しているために注釈を配置する特定の場所がない場合、データノードは現在のモデルの新しいルートとしてアタッチされます。

データを含むノードを生成する移行スクリプトは、そのようなノードの概念を宣言し、モデルにそのような注釈をそれぞれ挿入するためにputData () 構造を使用する必要があります:

producedata

データを含むノードは、データが生成されたモジュールに応じて、他のモジュールで実行されている他の移行スクリプトによって取得できます。

requiredata

移行スクリプトの順序

注釈データ必要とし、注釈データセクションを生成 することによって表現される移行スクリプト間の暗黙の依存関係は、移行スクリプトの正しい順序付けに注意を払うでしょう。スクリプトがいくつかのモジュールを移行するとき、このモジュールとそのすべての依存関係のために保存されたデータを使うことができるため、消費するスクリプトはモジュールのすべての依存関係で必要なすべてのプロデューサを走らせた後に初めてモジュールの移行を始めます。これらの依存関係を明示的に表現する必要はありません。

しかし、他のスクリプトが同じモジュールに対して実行された後でのみ(依存関係に注意を払わずに)あるスクリプトを実行する必要がある場合、そのような順序付け制約はexecute afterセクションを通して表現できます。たとえば、あるプロパティーがある概念からその概念(別の言語で宣言されている)に移動された場合、移行は2つの移行スクリプトで表すことができます。サブコンセプトに適用可能な最初のスクリプトは、古い非推奨プロパティーから新しいプロパティーにプロパティー値をコピーします。2番目のスクリプトはスーパーコンセプトに適用でき、サブコンセプトのインスタンスではないスーパーコンセプトのそのようなインスタンスの新しいプロパティーをデフォルト値で開始します。そして、2番目のスクリプトが、移動されたプロパティーの値に応じて他の初期化を行うとしましょう。2番目のスクリプトは最初のスクリプトの後にのみ実行し、すべてのモジュールで実行する必要があります。

移行を定義するための言語

jetbrains.mps.lang.migration言語は、移行スクリプトに固有のすべての概念を定義しています。マイグレーションを定義するときには、BaseLanguage言語とjetbrains.mps.lang.smodelおよび .query言語を一緒に使用してモデルを操作することができます。ofType <モデル>コンストラクトは、渡されたSModule:に含まれるモデルを取得するのに特に役立ちます。

sequence<SModel> models = m.getModels();&nbsp; models.ofType<model>.selectMany({~model => model.nodes(BaseDocComment); }).forEach({~node => ... });

通常の移行では、最初に移行アスペクトモデルを移行から除外し、次に移行が必要なノードをスキャンします。新しいノードが作成され、古いノードの値と子で初期化されます。その後、古いノードが新しいノードに置き換えられます。新しいノードのIDを古いノードのIDの値に設定すると、ターゲットを失うことなくこのノードへの参照を移行できます。

void execute(SModule m) { sequence<model> models = ((sequence<model>) m.getModels()).where({~it => !it.isAspectModel(migration); }); models.selectMany({~m => m.nodes(OldComponent); }).forEach({~oldNode => node<NewComponent> newNode = <NEW component $( oldNode.name )$ {>; *( oldNode.member )* ((SNode) newNode/).setId(((SNode) oldNode/).getNodeId()); oldNode.replace with(newNode); }); }

概略図

  1. 変換は何らかのノードに適用されます。その結果、古いノードへの参照(Noで呼び出し)と新しいノード(Nn)への参照があります。

  2. Noの子孫のIDは自動的に保持されます。もし変換された子孫ノードが変換後の出力ノードの子孫である場合、すでに同じIDを持ちます。

  3. No:MPSのIDは、Noが出力ノードの子孫であるかどうかを決定します。
    1. もしそうなら、すでにNoを指している参照のターゲットを持っています。(これは「折り返し」の場合です - 変換の結果として、ノードは別のノードに「折り返されます」。)

    2. いいえの場合、NnはNoのIDを取得します。(これは、ノードの概念を変更した場合ですが、古いノードは新しいものと意味的に同じです。)

  4. 包含モデルでは、NoはNnに置き換えられます。

コンセプト交換

言語設計者が言語の概念を削除して、おそらく新しい概念に置き換えることにした場合、言語の概念定義をすぐに言語から削除しないでください。代わりに、この概念を最初に非推奨にし、ユーザーコードを非推奨の概念から移行するための移行スクリプトを提供する必要があります。

廃止予定のコンセプトは、廃止予定のコンセプトの後のバージョンでは完全に削除できます(ただし、削除する必要はありません)。廃止予定のコンセプトを参照している移行スクリプトも削除されました。

プロジェクト移行の定義

プロジェクトの移行は通常、言語開発者ではなく、MPSチームがモデルファイル形式の変更、モジュールの依存関係システム、その他のプロジェクト全体のことを記述するために使用します。

プロジェクトの移行はプロジェクト全体に対して実行されるため、プロジェクトの一部が変更された場合にMPS開発者がどのように移行するのかを考えるのはMPS開発者の責任です。たとえば、ユーザーはVCSから自分のプロジェクトを更新できます。この場合、プロジェクトが一度移行されたことを知るだけでは不十分な場合があります。更新されたモジュールはまだ移行する必要があるかもしれません。
MPSはプロジェクトの移行が実行される順序を保証するものではないため、基本的には相互に依存するプロジェクトの移行を書くことはできません。

それにもかかわらず、ユーザーは独自のプロジェクト移行を書くことができます。プロジェクト移行のための特別な言語はないため、それらは基本的にJava / BaseLanguageクラスとして書かれており、plugin.xmlを通して提供されています。それで、すでにMPSプラグインを既に持っていて、その中にプロジェクト移行を書くとさらに仮定します。

プロジェクトの移行がソリューションで記述されている場合、このソリューションではソリューションのプロパティーダイアログファセットタブアイデアプラグインを有効にし、アイデアプラグインタブでプラグインIDを設定する必要があります。

新しいプロジェクト移行の追加

  • プロジェクト移行インターフェースを実装する移行用のクラスを作成します。ほとんどの場合、BaseProjectMigrationクラスから継承すると便利です。

  • 新しいマイグレーションに貢献するApplicationComponentを作成してください: plugin.xmlに登録することを忘れないでください

  • ProjectMigrationsRegistry.addProjectMigration()メソッドを使用して、作成したApplicationComponentからすべてのプロジェクト移行に貢献する

プロジェクト移行からのデータの保存

プロジェクト移行ではMigrationPropertiesプロジェクトコンポーネントを使用してデータを永続化できます。永続化されたデータはプロジェクトの.mpsフォルダーに格納されるため、VCSを介してプロジェクトの開発者間で共有されます。

マルチブランチ

複数のブランチを使用するプロジェクトを移行することには、さらにいくつかの課題があります。詳細については分岐を伴う移行の使用のドキュメントをチェックしてください。

移行Antタスク

Antスクリプトからプロジェクト内のすべてのマイグレーションを実行するためのAntタスクがあります。このタスクは、移行の自動テストやプロジェクトが移行されたかどうかの確認に使用できます。

このタスクではMPSホームパスを以下のように設定する必要があります

  1. mpshomeタスク属性を定義しますか、

  2. mps_home環境プロパティーを定義しますか、

  3. mps.home環境プロパティーを定義する - これが推奨する方法です

ホームパスは、build.txtファイルを含むフォルダーへのパスです: 例: Mac OSではこれは "/ Contents /"で終わります

リポジトリの内容は<repository>タグを使用して指定できます。

Screen Shot 2017 10 25 at 20 56 56

プロジェクトをマイグレーションするためにプラグインが必要な場合は、これを<migrate> antタスクで指定できます。対応するプラグインは、その依存関係とともに有効になります。

MigratePlugins

サンプル

マイグレーションを定義する方法の具体例については、MPSにバンドルされているマイグレーションのサンプル・プロジェクトを調べましょう。相互に相互接続された2つの単純な言語を移行するための移行スクリプトが表示されます。一方はデータを使用して2つの移行スクリプト間で移行されたノードに関する情報を渡し、もう一方はノードIDの操作に依存します。

ローカル・ヒストリービューでの移行による変更

移行はローカル・ヒストリー機能と連携します。

lh1

移行を実行した後、各移行によってプロジェクトに加えられたすべての変更を確認することが可能です。プロジェクトのフォルダー、モジュール、またはモデルの「ローカル・ヒストリー」ビューを開き、2つの変更を選択してCtrl + Dを押して違いを確認します。

lh2
lh3

ローカル・ヒストリービューと差分ダイアログから、変更または変更のグループを元に戻すこともできます。

IntelliJ IDEAの移行アシスタント

IntelliJ IDEAプラグインは言語の移行も実行できます。MPS自体と同様に、移行アシスタントはIDEAプロジェクトのモデルを、現在インストールされている使用言語のバージョンと一致するように更新します。

IDEA Migration1

非推奨コードの発見

非推奨は、ある言語の次のバージョンのいずれかで要素が削除されることを言語のユーザーに示すための推奨メカニズムです。MPSは、ユーザーが廃止予定のコードを排除するのに役立ついくつかの便利なファインダーを提供します。廃止予定の使用箇所の検索は廃止予定の要素のすべての用法を見つけることができます。検出された使用箇所のレポートでは、コード削除の予定バージョンごとにエントリがグループ化されています。これにより、その深刻度を認識し、排除することを優先することが容易になります。

Migx

最終更新日: 2019年8月30日