Lima で Artifact Registry に接続する

仕事で m3 mac 使ってて、 Lima を使ってコンテナを利用している。 Artifact Registry への認証の仕組みを整備しているので、備忘のためメモ。

前提は direnv 使ってディレクトリごとに認証情報とか設定を環境変数で切り替えてる。 Google 認証情報も Application Default Credentials (ADC)主体。

環境

  • macOS Sequoia
  • Lima 2.0.3

方針

  1. ホスト側で ADC を管理する
  2. Lima VM へ環境変数を伝搬する
  3. VM 内では docker-credential-gcr を利用する
  4. Artifact Registry 認証は docker-credential-gcr に委譲する

つまり認証情報はホスト側へ集約。lima vmは参照のみ。

構成は以下:

Host
 +- ADC
 +- wrapper script
 +- Lima

Lima VM
 +- docker-credential-gcr
 +- nerdctl + containerd / docker + dockerd

Lima VM の準備

VM 内へ docker-credential-gcr を導入する。これは Lima VM のスタートアップスクリプトを仕込む。 またホスト側のホームディレクトリはマウントしておく。 ADC の application_default_credentials.json はホーム以下に存在する前提。 docker-credential-gcr は latest を取得しているため、再現性を重視する場合は取得するリリースを固定する。

# lima.yaml
provision:
- mode: system
  script: |
    #!/bin/bash
    
    set -e -u -o pipefail
    
    # Global variable for secure temporary directory (for exit trap scope)
    __temp_dir=""
    
    # Check if a list of required commands are installed and available
    check-required-commands() {
        local cmd
        for cmd in "$@"; do
            if ! command -v "${cmd}" >/dev/null 2>&1; then
                printf "ERROR: '%s' is required but not installed.\n" "${cmd}" >&2
                return 1
            fi
        done
    }
    
    # Fetch the latest release asset URL for the target repository
    get-latest-asset-url() {
        local api_url='https://api.github.com/repos/GoogleCloudPlatform/docker-credential-gcr/releases/latest'
        local url
        url="$(curl -sSf "${api_url}" | jq -r '.assets[] | select(.name | contains("linux_arm64")) | .browser_download_url')"
        if [[ -z "${url}" || "${url}" == "null" ]]; then
            return 1
        fi
        printf "%s\n" "${url}"
    }
    
    main() {
        # 1. Verify required commands are available
        if ! check-required-commands jq curl tar; then
            return 1
        fi
    
        # 2. Fetch the latest release asset URL via helper function
        printf "Fetching latest release metadata from GitHub API...\n"
        local download_url
        if ! download_url="$(get-latest-asset-url)"; then
            printf "ERROR: Failed to find asset in the latest release.\n" >&2
            return 1
        fi
        printf "Found asset URL: %s\n" "${download_url}"
    
        # 3. Create a secure temporary directory and assign to global variable
        __temp_dir=$(mktemp -d -t docker-credential-gcr-bootstrap-XXXXXX)
        # Ensure cleanup of the temp directory on exit or error (runs in global scope)
        trap '[[ -n "${__temp_dir}" ]] && rm -rf "${__temp_dir}"' EXIT
    
        # 4. Extract archive name from the URL and download/extract it inside the temporary directory
        local archive_name
        archive_name=$(basename "${download_url}")
        printf "Downloading asset '%s' to temporary directory: %s\n" "${archive_name}" "${__temp_dir}"
        curl -sSfL -o "${__temp_dir}/${archive_name}" "${download_url}"
    
        printf "Extracting archive...\n"
        tar -xzf "${__temp_dir}/${archive_name}" -C "${__temp_dir}"
    
        # 5. Move the binary to /usr/local/bin directly (mv fails strictly if file is missing)
        local binary_name="docker-credential-gcr"
        local dest_dir="/usr/local/bin"
        printf "Moving binary to %s ...\n" "${dest_dir}"
        mv "${__temp_dir}/${binary_name}" "${dest_dir}/"
        chmod +x "${dest_dir}/${binary_name}"
        printf "Successfully installed docker-credential-gcr to %s/%s!\n" "${dest_dir}" "${binary_name}"
    }
    
    main "$@"

Lima VM を起動して、 ~/.docker/config.json に以下の認証ヘルパが登録されていたらOK:

{
  "credHelpers": {
    "asia-northeast2-docker.pkg.dev": "gcr"
  }
}

環境変数の伝搬

ホスト側でラッパースクリプトを用意し、パスを通しておく。 これで単にホストからラッパースクリプトを叩くだけで、透過的に扱える。 以下の例では、 lima コマンドに渡すコマンド exec に対して、変数をコマンドスコープで指定している。

#!/bin/bash

# lima whichなど、limaコマンドを指定コマンド実行前に実行すると、STDINが消費されてしまう
# 明示的に退避が必須
__command='nerdctl'
if lima which docker </dev/null >/dev/null 2>&1; then
    __command='docker'
fi
__env=()
if [[ -n "${GOOGLE_APPLICATION_CREDENTIALS:-}" ]]; then
    __env+=("GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS}")
fi
exec lima "${__env[@]}" exec "${__command}" "$@"

動作確認

ホスト側で以下のように、Artifact Registry から pull & push を実行する。

docker pull asia-northeast2-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG
docker push asia-northeast2-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG

メモ

Lima VM 内へ Google Cloud SDK を導入する構成も考えられるが、以下の理由で筋悪いなと思って採用してない。

  1. VM ごとに gcloud を管理したくない
  2. VM ごとに認証状態を持たせたくない
  3. 認証情報の管理箇所を増やしたくない

また、ADC ファイルを VM 側へコピーする構成も論外。認証情報を複製したくなかったため、ホスト側で管理する前提とした。

まとめ

  1. ADC はホスト側で管理
  2. Lima VM へ環境変数を伝搬
  3. docker-credential-gcr を利用
  4. Artifact Registry 認証は helper に委譲

これでホスト側の認証情報を管理するだけで、Lima VM 側に透過的に認証状態を参照させることが可能。 Lima VM はたまに再作成するので、気軽に消せるようになって大変よろしい。

参考文献

  1. https://github.com/lima-vm/lima/blob/v2.0.3/templates/default.yaml
  2. https://github.com/googlecloudplatform/docker-credential-gcr

VimでJavaを書く方法 2026年版

2026年現在、 Vim で Java を書く方法を調べると、ほぼ確実に Eclipse JDT Language Server (JDT LS) に行き着きます。 補完、定義ジャンプ、リファクタリングなど、Java開発に必要な機能は一通り揃っており、非常に有力な選択肢となります。

では他の選択肢を探してみます。

なんということでしょう、見つけられませんでした。

もちろん過去には eclim や javacomplete など様々な試みがありました。しかし2026年現在、積極的に選択肢として挙げられるものは JDT LS くらいです。

困りました。 比較記事を書こうと思ったのですが、比較対象がありません。 比較記事を書くには、まず選択肢を列挙する必要があります。

そこで go-jls という選択肢を1つ、新たに作成しました。 折角なので、自分が欲しいものを作ることにしました。 面倒なので、細かいことはリポジトリの README をご参照ください。

https://github.com/kamichidu/go-jls/blob/v0.0.0/README.adoc

さて今日の記事では、

  • Vim + JDT LS
  • Vim + go-jls

この2つを比較してみます。 2026年6月12日時点での比較となります。

JDT LS は Eclipse JDT を利用した Language Server です。 そのため Java の解析や補完については、長年 Eclipse が蓄積してきた資産を利用できます。

JDT LS が強い理由も、ある意味では単純です。 元になっている Eclipse が強いからです。

ところで JDT LS って実質 Eclipse を持ってきてるんですよね。 私自身 Eclipse にはかなり思い入れがありますし、なんなら今でも使っています。 Java をがっつり書く必要があるときは大体 Eclipse でした。

Eclipse Rich Client Platform を利用した業務アプリケーション開発なんかもやっていました。 あれは良いですね。 Java の機能が一通り使えますし、GUI 部品なんかも良い抽象度で提供されています。 カスタム部品なんかも作っていました。 パラメータとか全部 Object 型でしたけどね。

そんな訳で Eclipse に対する印象はかなり良いです。 JDT LS についても同様で、2026年現在の標準的な選択肢と言って良いでしょう。

比較するとこんな感じです。

項目 JDT LS go-jls
補完
定義ジャンプ
自動 import
リファクタリング ×
Maven / Gradle 連携
エラーチェック ×
Vim 親和性
  • ○ = 対応
  • △ = 一部対応または制限あり
  • × = 未対応

面倒なので、細かい機能紹介とかは世の中にたくさん記事があります。そちらをご覧ください。 しかし JDT LS は本当に強い選択肢です。導入は面倒ですし、私がシェル世界の住人であるため、起動から動作するまでが結構かかる印象です。なので使わなくなっちゃいました。 基本的に Eclipse 起動してます。

一方で、go-jls でも私が普段欲しい機能は一通り揃うようになってきました。 go-jls は私が作成した Java Language Server です。 まだ未実装の機能もありますし、JDT LS と比較すると足りない部分も多くありますし、万人向けではありません。 ただ自分で作って使っていますが、今のところ私は特に困っていません。 このサクサクと思考を邪魔しない動作が私は好きです。

さて、これで Vim で Java を書く選択肢が1つ増えました。 良かったですね。

参考文献:

vim-javim の実装範囲

前回 は Pure Vim script で Java Virtual Machine (JVM) を実装し、Vim から Java を実行する方法を紹介しました。

Java を動かそうとすると、Garbage Collection (GC) やスレッド管理など様々な構成要素が登場します。 ただし、Java を動かすための最小実装はもっと小さいです。

本記事では、公開時点の vim-javim の実装範囲について整理します。

https://github.com/kamichidu/vim-javim/tree/54711c41b96d0e5578a8a5afab83493abeebdc4f

実装状況

実装状況は下表の基準で分類しています。

Status Meaning Description
Full 対象範囲を実装済み vim-javim の現在の実行モデルで必要な範囲を実装
Partial 部分実装 HelloWorld / Fibonacci など、公開時点の実行対象に必要な範囲を中心に実装
Unimplemented 未実装 公開時点では未対応

公開時点の実装状況を下表に示します。

JVMS Section Area Status Note
4 Class File Format Partial class file の基本構造を読み込む。対応属性や検証は限定的
4.3 Descriptors Full method descriptor を解析し、引数型と戻り値型を扱う
4.4 Constant Pool Partial "Utf8", "Integer", "Long", "Class", "String", "Fieldref", "Methodref", "NameAndType" などを扱う
4.5 Fields Partial field 情報を読み込み、static / instance field の解決に利用
4.6 Methods Partial method 情報を読み込み、"Code" attribute を実行対象として扱う
4.7 Attributes Partial "Code" を中心に扱う。"LineNumberTable" など実行に不要な属性は読み飛ばし
5.3 Loading Partial classpath directory / jar extraction cache / built-in runtime から class を読み込む
5.4 Linking Partial 検証は行わず、必要な解決処理と static field へのデフォルト値割り当てを実装
5.5 Initialization Full "()V" を class loading 時に実行
2.5 Runtime Data Areas Full heap, method area, static fields, pc, stack / frame 相当を Vim のデータ構造で管理
2.6 Frames Full Local Variables と Operand Stack を frame 単位で管理
2.9 Special Methods Partial "" と "" を扱う
2.10 Exceptions Unimplemented "athrow" や例外伝播は未実装
2.11, 6 Instruction Set Partial int / reference 系の基本命令、分岐、field access、method invocation を中心に実装
2.8 Floating-Point Arithmetic Unimplemented float / double 系の演算は未実装
2.5.6 Native Method Stacks Unimplemented native method stack は未実装
2.11.10 Synchronization Unimplemented monitor / synchronization 系は未実装

詳細な対応状況については、以下のリンク先を参照:

実装対象選定

まず動くJVMを作ることを優先し、公開時点では実行対象の Bytecode から必要仕様を逆算する方針を取りました。

Bytecode は "javap" コマンドで確認できます。

HelloWorld

例えば、前回利用した HelloWorld を見てみます。

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

"javap -c" の結果は以下:

Compiled from "HelloWorld.java"
public class test.classes.HelloWorld {
  public test.classes.HelloWorld();
    Code:
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return

  public static void main(java.lang.String[]);
    Code:
         0: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #13                 // String Hello, World!
         5: invokevirtual #15                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
}

HelloWorld の "main()" では、

  • "java.lang.System.out"
  • "java.io.PrintStream.println(String)"

が利用されています。 また、コンストラクタでは "java.lang.Object.()V" が呼び出されています。

そのため、 Opcode の実行だけではなく、少なくとも以下の機能が必要になります。

  • ClassFile Format
  • Constant Pool
  • Frame
  • Operand Stack
  • Local Variables
  • Static Field Resolution
  • Method Invocation
  • Java SE Runtime

Fibonacci

次に Fibonacci を見てみます。

public class Fibonacci {
    public static int fib(int n) {
        if (n <= 1) {
            return n;
        }

        return fib(n - 1) + fib(n - 2);
    }
}

"javap -c" の結果は以下:

Compiled from "Fibonacci.java"
public class test.classes.Fibonacci {
  public test.classes.Fibonacci();
    Code:
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return

  public static int fib(int);
    Code:
         0: iload_0
         1: iconst_1
         2: if_icmpgt     7
         5: iload_0
         6: ireturn
         7: iload_0
         8: iconst_1
         9: isub
        10: invokestatic  #7                  // Method fib:(I)I
        13: iload_0
        14: iconst_2
        15: isub
        16: invokestatic  #7                  // Method fib:(I)I
        19: iadd
        20: ireturn

  public static void main(java.lang.String[]);
    Code:
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: bipush        10
         5: invokestatic  #7                  // Method fib:(I)I
         8: invokevirtual #19                 // Method java/io/PrintStream.println:(I)V
        11: return
}

Fibonacci では、

  • 条件分岐
  • 整数演算
  • static method invocation

が利用されています。 また、"fib()" は再帰呼び出しを行います。 そのため、method invocation ごとに独立した実行状態を保持する必要があります。 公開時点の vim-javim では、このための Frame および Operand Stack を実装しています。

上述の通り、HelloWorld や Fibonacci の実行に必要な範囲だけを見ると、JVMS 全体のうち実際に必要となる仕様は限定的です。 そのため、公開時点では必要仕様を優先して実装しています。

Java を動かすためのその他の構成要素

ClassFile を読み込み、Opcode を実行できるだけでは Java は動作しません。 例えば HelloWorld を実行するだけでも、

  • "java.lang.Object"
  • "java.lang.String"
  • "java.lang.System"
  • "java.io.PrintStream"

などが必要になります。

これらは JVMS ではなく Java SE API の領域です。 通常は Java Runtime が提供するクラスライブラリを利用しますが、vim-javim では Java Runtime へ依存せず、plugin 内で built-in runtime を提供しています。 また、依存クラスの解決を行う ClassLoader 相当の仕組みについても javim 独自実装となっており、 classpath や built-in runtime の解決もここで実装しています。

※ built-in runtime だからといって高速になる訳ではありません。vim-javim は Pure Vim8 script による実装であり、一般的な JVM と比較すると性能面では大きく劣ります。

まとめ

本記事では公開時点の vim-javim の実装範囲について整理しました。 公開時点では、実行対象の Bytecode から必要仕様を逆算し、実装対象を選定しています。 詳細な実装状況についてはリポジトリを参照してください。

参考文献

VimでJavaを実行する方法 2026年最新版

どうも、kamichiduです。

この記事は Vim 駅伝 2026-06-03 の記事となります。

早速ですがみなさん、開発をしていて Vim から Java を実行したいと感じたことはないでしょうか。 私はあります。 特にちょっとしたコードやアルゴリズムを試したいとき、端末へ切り替えたり、ビルドしたり、実行したりという往復は意外と面倒です。

そこで今回は、Vim から Java を実行する方法について紹介します。

先に実行環境は以下です:

  • Vim: 9.1.2100
  • Java Runtime: 25.0.2
  • OS: macOS arm64

なお、本プロジェクトは Vim9 script ではなく Vim8 script で実装しています。 特に Vim9 固有機能を必要としておらず、可搬性を優先しています。

さて、Vim から Java を実行するときの代表的な方法といえば、やはりコマンド実行でしょう。

:!java package.Class

というやつです。 もちろんこれでも動きます。 ただこの方法、Java の悪名高き起動コストが効きます。 それはもう効きます。 HelloWorld 程度ならともかく、ちょっと試したいだけなのに JVM の起動を待つのはあまり嬉しくありません。

Java の起動が遅いなら、Java を起動せずに実行すれば良いのではないでしょうか。 つまり、Pure Vim script で Java Virtual Machine (JVM) を実装すれば、Java を起動せずに Java を実行できます。

幸い、過去に通勤電車で Java Virtual Machine Specification (JVMS) を読んでいたため、実装方針自体は把握しています。 ClassFile を読み込み、Frame を実装し、Bytecode Interpreter を作れば、とりあえず動くはずです。 そのため今回、JVMS に従って Java のコンパイル済み ClassFile を実行する Vim plugin を実装しました。

GitHub: https://github.com/kamichidu/vim-javim

現在のところ、

  • ClassFile の読み込み
  • Constant Pool の解釈
  • JVM Frame
  • Bytecode Interpreter
  • メソッド呼び出し
  • 分岐命令
  • 整数演算

あたりを実装しています。

HelloWorld は動きます:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
:JavimRun test.classes.HelloWorld
Hello, World!

Fibonacci も動きます:

public class Fibonacci {
    public static int fib(int n) {
        if (n <= 1) {
            return n;
        }

        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        System.out.println(fib(10));
    }
}
:JavimRun test.classes.Fibonacci
55

とりあえず Java は動いていると言って良さそうです。

これで Java 起動コストを気にせず、 Vim から Java を実行できるようになりました。 Vim script の表現力がさらに増えて嬉しいですね。

続き書きました:

参考文献:

terraform cli 備忘録

google providerなどのpluginはファイルサイズがでかくなる。 色んなフォルダでinitしまくると、ディスク容量を圧迫する。

~/.terraformrc で plugin_cache_dir を設定すると、設定したフォルダをpluginの実体ファイル置き場にでき、ディスク容量の圧迫度合いがマシになる。

環境変数 TF_CLI_CONFIG_FILE で、設定ファイルパスを変更可能。

terraformプロセスを実行するユーザが、plugin_cache_dir への書き込み権限などを持っている必要あり。

MC IC2 Replication memo

Version

  • Minecraft 1.12.2
  • Industrial Craft 2 2.8.142-ex112
  • Build Craft 7.99.24.1

Required UU-Matter

Name *1 UU-Matter * 1 UU-Matter * 64
Block of Redstone 7.185 mB 459.84 mB
Bronze Block 7.2 mB 460.8 mB
Bronze Item Casing 0.4778 mB 30.5792 mB
CF Powder 18.55 mB 1187.2 mB
Clay (ball) 17.34 mB 1,109.76 mB
Clay (block) 69.39 mB 4,440.96 mB
Copper Block 6.896 mB 441.344 mB
Copper Cable 0.3017 mB 19.3088 mB
Copper Dust 0.7651 mB 48.9664 mB
Crystal Memory (raw) 487,900 mB 31,225,600 mB
Crystal Memory 487,900 mB 31,225,600 mB
Ender Pearl 1,001 mB 64,064 mB
Flint 0.5849 mB 37.4336 mB
Glass Fibre Cable 11.96 mB 765.44 mB
Glass 0.290 mB 18.56 mB
Gold Ore 10.15 mB 649.6 mB
Heat Conductor 606.6 mB -
Iridium Ore 120 mB 7,680 mB
Iridium Reinforced Plate 519.6 mB 33,254.4 mB
Iridium Shard 13.33 mB 853.12 mB
Lapis Lazuli Block 37.5 mB 2,400 mB
Obsidian 433,100 mB 27,718,400 mB
Saddle 27.07 B -
Silicon Dioxide 139.2 mB 8,908.8 mB
Silver Dust 47.58 mB 3,045.12 mB
Silver Ingot 47.72 mB 3,054.08 mB
Sponge 66.63 B -
Steak 88.32 mB 5,652.48 mB
Tin Block 8.022 mB 513.408 mB
Tin Cable 0.3434 mB 21.9776 mB
Tin Can 0.6634 mB 42.4576 mB
Tin Dust 0.8902 mB 56.9728 mB
Tin Item Casing 0.5234 mB 33.4976 mB
Tiny Pile of Silver Dust 5.285 mB 338.24 mB

Unable to Replicate

  • Universal Fluid Cell
  • Tank (Build Craft)
  • Any Tank (Fluid Tank)
  • Any Machine (Industrial Craft2)

*1:A to Z order

git tips

稀によく使うものをメモ

# 履歴に関連のないhogeとfugaとをdiff
git diff hoge..fuga

# hogeブランチのxxxフォルダと、fugaブランチのyyyフォルダとをdiff
git diff hoge:xxx fuga:yyy
git diff hoge:xxx..fuga:yyy
git diff hoge:xxx...fuga:yyy