きどたかのブログ

いつか誰かがこのブログからトラブルを解決しますように。

Gradle MVS Dataset Plugin試作品 - Gradle Nested Container

データセットをgradleから作るようにする。


必要となるもの:
 gradle ssh plugin
 USSのtsocmdコマンド
 TSO/E ALLOCATEコマンドの知識

仕組み:
 Linux/Windowsでgradleを動かして、z/OSにsshしてtsocmdでデータセットを作成する。
 

こんな感じでbuild.gradleに書く。

datasets {
    "hlq.aaa" {
        vol = 'VOL001'
        dsorg = 'PS'
        recfm = 'F,B'
        lrecl = 80
        space = '(10,10) TRACKS'
        initialData {
            srcEncoding = '1208'
            destEncoding = '1047'
        }
    }
    "hlq.bbb" {
        vol='VOL002'
        dsorg='PO'
        members {
            "MYJCL" {
                initialData {
                    srcEncoding = '1208'
                    destEncoding = '1047'
                }
            }
        }
    }
}

もっと省略して書けるようにすることもできるだろう。
上の例では、POならDSNTYPE(PDS)やろ的な省略をしているし、lrecl未指定なら80やろ的な省略をしている。


プラグインはこんな感じで書く。

import org.gradle.api.Plugin
import org.gradle.api.Project

class DatasetPlugin implements Plugin<Project> {
    void apply(Project project) {
        def datasets = project.container(Dataset){
            String name ->
            def dataset = project.extensions.create(name,Dataset,name)
            dataset.extensions.create('initialData',InitialData,'initialData')
            dataset.extensions.members = project.container(PDSMember){
                String memberName -> 
                def member = dataset.extensions.create(memberName,PDSMember,memberName,dataset)
                member.extensions.create('initialData',InitialData,'initialData')
                member
            }
            dataset
        }
        project.extensions.datasets = datasets
    }
}

PDSMemberのところが、コンテナの中にコンテナを作ってる箇所。


Datasetクラスは、TSO/E ALLOCATEコマンドのパラメータから作成する。
Datasetクラスには、generateAllocCmd()などを定義して、sshのexecuteに渡すコマンドを組み立ててリターンするようにする。
そのコマンドは、こんな感じに組み立てる。
"ALLOCATE DATASET('hlq.aaa') VOLUME(VOL001)...."


sshセッションで使うときは、こんな感じに書ける。
execute "tsocmd \"" + datasets['hlq.aaa'].generateAllocCmd() + "\""
なんかメソッド長いから、コマンド用クラスを挟んで、datasets['hlq.aaa'].cmd.alloc()みたいにしようかな。



入れ子構造がほしかったのは、初期データを順次データセットにぶち込みたいから。
それと、PDSメンバを管理し、PDSメンバも初期データをぶち込みたいから。


初期データには、まだfileプロパティを書いていないが、イメージはある。

initialData {
    srcEncoding = '1208'
    destEncoding = '1047'
    file = sourceSets['test'].output.resources.getAsFileTree.matching{include '**/MYJCL.jcl'}.getSingleFile()
}

いったんUSSに配置して、iconvかけて、cpコマンドでデータセットに持っていく。
それをするために、エンコーディングを持たせているが、
初期値を1208,1047に設定してしまえば、より簡潔に書けることになる。


データセット作成機能:
上述のようなやり方でallocateは実現できます。


データセット初期データ機能:
iconvとcpコマンドで実現。mvでもいいかな。
おそらくInitialDataにcpコマンドのオプションをもう少し持たせる必要があるかもしれない。
また、改行コードの扱いも面倒。CRはsedで取り除くのかな。cpコマンドのオプションで、crnlとかもあったはず。


データセット存在確認:
tsocmdでLISTDSを使い、その標準出力をgrepかけて判定することで可能。


データセット削除機能:
tsocmdでFREEを使えばできる。
PDSメンバだけをFREEできるのかは不安要素、できそうなことは書いてる。


データセット圧縮機能:
んー、まだ調べ切れていない。
できる気はしていない。
PDSEにしなよって話か。


DatasetクラスとPDSMemberクラスは、descriptionプロパティをつけておく。
実はPDSMemberクラスはdescriptionプロパティしかない。。。
説明は大事。なんのためのデータセットだよ、分かんねーよ。


コードは日々改良を重ねている。PDSメンバのデータセットに初期データをぶちこむには、PDSMemberクラスのコンストラクタに、ExtensionAwareになってるDatasetクラスを渡して名前を組み立てさせるのはよさそうだ。


PDSメンバをssh経由でこねくるときは、括弧がついてるせいで、ダブルクォートで囲むなどしないといけないのが面倒臭いな。。。


このエントリーで書いてる書き方だと、すごく縦に長くなっていくから、実際には、セミコロンを使って今は横長にしてる。
書き方については、もっと工夫ができて、例えばDatasetクラスにjcllib(Map properties)を書いて、いくつかのパラメータは省略にしつつ、引数は横長にMap Expressionで書けるようにさせることができる。
ボリューム名は必須。dirやspaceは書いてほしいが、書いてなくても初期値を用意する。
ほかには、ログ出力としての置き場になってるところはspaceパラメータを多めにした簡易定義メソッドを用意してあげるとか。


recfmや、spaceの書き方を不思議に思われるかもしれないが、こっちのほうが楽にいける。


データセット名の一部を-Pで渡した値にすることもできている。システム名だとか、ホスト名だとか、ボリューム名だとか。
これができることは大事だ。


DatasetやらPDSMemberがExtensionAwareになっているのを利用して、どのテストに必要なのか印を付けられなくもない、しかし実際にはTestタスクで動くものとの連動はイメージがわかない。


ほかには、MVSデータセットと、リポジトリの資材が本当に同期しているかの確認を処理させることも考えられるかも。いや、processTestResourceなどで書き換えるので差分は出てしまうなぁ。これはやめておこう。


あー、マルチボリュームもできるのかを検証しとらんわー。ニーズは極小だから後回しかな。


まじ、やりたいことがたくさんある。