カナデKanade

パッケージを使う・作る

hana addで他の人が作ったパッケージを使い、自分のパッケージを作って配る方法を知りましょう。

パッケージは、誰かが(あるいは自分が)作っておいた関数とクラスのまとまりです。Hanaランタイムには、パッケージをダウンロードして管理するコマンドが入っています。パッケージはgitリポジトリで、名前がそのままリポジトリのアドレスです。中央サーバーはありません。ブラウザの実行ボタンではパッケージは使えず、Hanaランタイムで実行するときだけ使えます。

パッケージを使う

プロジェクトのフォルダでパッケージを追加します。gitがインストールされている必要があります。

hana add github.com/owner/repo

この1行がすることは次のとおりです。

  • リポジトリのv1.2.0や1.2.0のようなバージョンタグのうち、一番高いものを選びます。
  • そのバージョンを自分のコンピューターのキャッシュフォルダ(~/.hana/pkg)にダウンロードします。フォルダは環境変数HANA_HOMEで変えられます。
  • そのパッケージが必要とするほかのパッケージも一緒にダウンロードします。
  • プロジェクトのフォルダにhana.jsonとhana-lock.jsonを書きます。

バージョンを自分で決めるには@を付けます: hana add github.com/owner/repo@1.2.0。

あとは、リポジトリのパスをそのまま【】の中に書いて持ってきます。ほかの標準モジュールとまったく同じ見た目です。

【github.com/owner/repo】から〈挨拶〉を持ってこよう
〈挨拶〉(「カナデ」)を出力しよう

パッケージは、ハリ用とカナデ用のエントリポイントを別々に持てます。自分のスクリプトの言語に合うエントリポイントがないと、「この言語のエントリポイントがありません」というエラーになります。

hana.jsonとhana-lock.json

{
  "dependencies": {
    "github.com/owner/repo": "1.2.0"
  }
}

hana.jsonは自分が求めるものです。書かれたバージョンは「このバージョン以上」を表す最小バージョンです。^や~のような範囲の書き方はありません。

{
  "github.com/owner/repo": {
    "version": "1.3.4",
    "commit": "a1b2c3d4e5f6..."
  }
}

hana-lock.jsonは実際に選ばれたものです。正確なバージョンと、そのときそのバージョンのタグが指していたコミットが書かれます。自分が追加したパッケージだけでなく、そのパッケージが必要とするパッケージもすべて入ります。2つのファイルをgitに一緒に上げておけば、別のコンピューターでhana installを1回実行するだけで、同じバージョンがダウンロードされます。

同じパッケージが複数の場所から別々の最小バージョンで求められたら、求められたうちで一番高いバージョンを1つだけ選びます。最小バージョンだけを書くので、「条件が合わなくてインストールに失敗する」ことはありません。

別のコンピューターで、そのほかのコマンド

コマンド できること
hana install hana-lock.jsonに書かれたパッケージをすべてダウンロードします。lockがhana.jsonに足りなければ、バージョンを選び直します
hana remove github.com/owner/repo パッケージを外します。そのパッケージのためだけに必要だったものもlockから消えます
hana list 使っているパッケージとバージョンを表示します。*は自分で直接追加したものです
hana why github.com/owner/repo そのパッケージがなぜ入っているかを表示します。自分で直接追加したのか、どのパッケージを経由して入ったのか(あ -> い -> repo)が分かります
hana outdated より新しいバージョンが出ているパッケージを表示します。上げるにはhana add パス@バージョンをもう一度実行します

hana runは何もダウンロードしません。パッケージがインストールされていなければ、「インストールされていません」というエラーでhana installを案内します。lockに書かれたコミットと実際にダウンロードしたコミットが違う場合(誰かがタグを動かした場合)は、インストールを拒否します。

自分のコンピューターにあるパッケージを直しながら使う

パッケージを作りながら、そのパッケージを使うプロジェクトも一緒に直すときは、hana.jsonにreplaceを書いて、ダウンロードの代わりに自分のフォルダを指すようにします。

{
  "dependencies": { "github.com/owner/repo": "1.2.0" },
  "replace": { "github.com/owner/repo": "../repo" }
}

replaceはこのプロジェクトでだけ有効で、lockには書かれません。

パッケージを作る

パッケージはgitリポジトリ1つです。フォルダ構成は次のとおりです。

repo/
├── hana.pkg.json
├── hari/
│   └── index.hr      ← ハリのエントリポイント
└── kanade/
    └── index.knd     ← カナデのエントリポイント

エントリポイントはどちらか片方だけでも構いません。エントリポイントの中の関数とクラスを、ほかの人が【github.com/owner/repo】から…を持ってこようで持っていきます。hana.pkg.jsonはパッケージ自身の情報です。

{
  "name": "github.com/owner/repo",
  "version": "1.2.0",
  "dependencies": {
    "github.com/owner/other": "2.0.0"
  }
}
  • nameはリポジトリのパスと同じでなければなりません(違うとインストールが拒否されます)。
  • dependenciesは、このパッケージが必要とするパッケージと最小バージョンです。パッケージ同士がぐるぐると互いを必要とすると、インストールが拒否されます。
  • エントリポイントのパスを変えるには、"entry": {"kanade": "src/main.knd"}のように書きます。
  • バージョンはgitのタグで決めます。新しいバージョンを出すときは、git tag v1.3.0を作ってプッシュします。

ネイティブライブラリを入れる

ハリやカナデでは難しいことは、GoやCなどで作ったライブラリ(.dll、.so、.dylib)に任せられます。OSごとに用意しておいたファイルをhana.pkg.jsonに書きます。

{
  "native": {
    "windows-amd64": {
      "file": "native/repo.dll",
      "url": "https://example.com/repo-windows-amd64.dll",
      "sha256": "…64桁…"
    },
    "linux-amd64": {
      "file": "native/librepo.so",
      "url": "https://example.com/librepo-linux-amd64.so",
      "sha256": "…64桁…"
    }
  }
}

hana addは今のコンピューターのプラットフォームの分だけダウンロードし、sha256が合っているか確認します。違えばファイルを捨ててインストールを止めます。リポジトリの中にファイルがすでに入っていれば(fileがあれば)ダウンロードしません。ライブラリが守るルールは、hanaリポジトリのnative/native.goに書かれています。

インストールスクリプト

用意したファイルを渡せず、インストールのときに自分でビルドしなければならないなら、インストールスクリプトを使えます。シェルを通さないコマンドの配列で書きます。

{
  "scripts": {
    "install": ["go", "build", "-buildmode=c-shared", "-o", "native/repo.dll", "./native"]
  }
}

スクリプトはコンピューターで自由に動くプログラムなので、そのままでは実行しません。

  • ユーザーがhana add github.com/owner/repo --allow-scriptsで承認する必要があります。承認するとhana.jsonのtrustedScriptsに書かれます。
  • 承認したスクリプトのハッシュがhana-lock.jsonに書かれます。スクリプトが変わると、承認し直すまで拒否されます。
  • ほかのパッケージが必要として付いてきたパッケージのスクリプトは、自動では許可されません。パッケージごとに別々に承認します。
  • スクリプトはhana addとhana installの中でだけ動きます。hana runは決して実行しません。
  • スクリプトを実行する前に、どんなコマンドかを画面に表示します。

承認していないスクリプトは、飛ばして案内だけを表示します。スクリプトにはサンドボックスがないので、信頼できるパッケージにだけ承認してください。

知っておくこと

  • パッケージの中の関数は、同じパッケージのほかの関数と、そのパッケージが持ってきたほかのパッケージを自由に呼べます。持っていく人がそれらを別に持ってくる必要はなく、自分のスクリプトに同じ名前の関数があってもお互いに邪魔しません。
  • パッケージの一番上で作った変数と文は、そのパッケージのものです。パッケージは最初に持ってきたときに1回だけ準備され(一番上の文が1回実行されます)、そのパッケージの関数はその変数を読んだり変えたりできます。あちこちから持ってきても、同じ変数を一緒に使います。反対に、自分のスクリプトの変数は、パッケージの関数からは見えません。
  • クラス名は、プログラム1つにつき1つです。別々の2つのパッケージ(または自分のスクリプト)が同じ名前のクラスを持っていると、持ってくるときにエラーで知らせます。片方を〈名前〉を〈別名〉に持ってこようで持ってきて、別の名前を付ければ大丈夫です。パッケージを作るときは、クラス名がほかと重ならないようにしてください。
  • パッケージのパスは、github.com/owner/repoのようにホスト名(ドットのある)とオーナーとリポジトリ名でできていなければなりません。リポジトリの中のサブフォルダをパッケージにすることはできません。
  • 非公開リポジトリもダウンロードできます。ダウンロードはコンピューターのgitが行うので、gitにログインしておく(資格情報マネージャー)か、sshキーを登録しておけば大丈夫です。ターミナルで実行すると、gitがログインを尋ねることもあります。sshのアドレスで取得したいなら、環境変数HANA_GIT_PROTOCOL=sshを設定してください(git@github.com:owner/repoで取得します)。ログインできないと、「ログインが必要な非公開リポジトリか、リポジトリが存在しません」と知らせます。
  • Hanaランタイムが一緒に配るtimezoneのようなパッケージは、hana addなしで名前だけで持ってこられます。
  • パッケージを使うプログラムを実行ファイルにまとめると、パッケージのハリ・カナデのコードはプログラムの中に入り、ネイティブライブラリは実行ファイルの隣に一緒に出力されます。
プレイグラウンド
結果
コードを書いて「実行」ボタンを押してください。