この記事はChatGPT-6 Atlasにより執筆されました。この記事の内容をまるっとcodexなどに渡すと実装してくれると思います。
--
気象・気候データの中身を確認するとき、私はよく ncview を使っています。
通常はターミナルで次のように実行します。
ncview sample.nc
ただ、Finderでファイルを探しているときは、そのままダブルクリックして開けると便利です。
そこで、Finderからファイルを受け取り、XQuartz経由でncviewを起動する小さなmacOSアプリを作成しました。この記事では、その作成方法とファイルの関連付けを紹介します。
動作確認した環境
- Apple Silicon搭載Mac
- macOS 27.0.1
- Homebrew版 ncview:
2.1.11_1 - XQuartz導入済み
この環境で、Finderから .nc ファイルを開き、ncviewが起動することを確認しました。
以下の手順は、ncviewが /opt/homebrew/bin/ncview にインストールされている環境を対象にしています。Intel Macや別のmacOSバージョンでの動作は未確認です。
仕組み
作成する ncview.app は、ncview本体を含まない起動用アプリです。
FinderでNetCDFファイルをダブルクリック
↓
ncview.appがファイルのパスを受け取る
↓
XQuartzを起動し、接続できるまで待つ
↓
インストール済みのncviewにファイルを渡す
アプリは、次の3つで構成します。
| ファイル | 役割 |
|---|---|
ncview-launcher |
Finderから「ファイルを開く」要求を受け取る |
launch-ncview.sh |
XQuartzを準備し、ncviewを起動する |
Info.plist |
アプリ名や、扱うファイル形式をmacOSに伝える |
1. ncviewとXQuartzを用意する
Homebrewが利用できる環境で、必要なものをインストールします。すでに導入済みなら、この操作は不要です。
brew install ncview
brew install --cask xquartz
参考:Homebrewのncview、HomebrewのXQuartz
XQuartzの初回インストール後は、ログアウトしてログインし直すと、DISPLAY 環境変数が更新されます。XQuartzのインストール案内
まずは、ターミナルから手元のNetCDFファイルを開けることを確認します。
ncview /path/to/sample.nc
以降のアプリ作成には、Command Line Toolsも必要です。
xcode-select -p
未インストールの場合は、次のコマンドから導入します。
xcode-select --install
2. 作業フォルダを作る
以下のコマンドは、同じターミナルで順番に実行してください。
mkdir -p ~/ncview-finder-build
cd ~/ncview-finder-build
mkdir -p ncview.app/Contents/MacOS
mkdir -p ncview.app/Contents/Resources
すでに同名のフォルダやアプリがある場合は、別の作業フォルダを使ってください。
3. Finderからファイルを受け取るプログラムを作る
Finderから渡されたファイルごとに、起動用スクリプトを実行します。
ファイルのパスはシェルコマンドの文字列に埋め込まず、NSTask の引数として渡します。これにより、ファイル名に空白が含まれていても、1つのパスとして扱えます。
cat > main.m <<'EOF'
#import <Cocoa/Cocoa.h>
@interface Launcher : NSObject <NSApplicationDelegate>
@end
@implementation Launcher
- (void)application:(NSApplication *)app
openFiles:(NSArray<NSString *> *)paths {
for (NSString *path in paths) {
NSTask *task = [NSTask new];
NSString *script = [[NSBundle mainBundle]
pathForResource:@"launch-ncview"
ofType:@"sh"];
task.executableURL = [NSURL fileURLWithPath:script];
task.arguments = @[path];
NSError *error = nil;
if (![task launchAndReturnError:&error]) {
NSAlert *alert = [NSAlert new];
alert.messageText = error.localizedDescription;
[alert runModal];
}
}
[app replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)app
hasVisibleWindows:(BOOL)flag {
NSOpenPanel *panel = [NSOpenPanel openPanel];
panel.allowsMultipleSelection = YES;
if ([panel runModal] == NSModalResponseOK) {
NSMutableArray *paths = [NSMutableArray new];
for (NSURL *url in panel.URLs) {
[paths addObject:url.path];
}
[self application:app openFiles:paths];
}
return NO;
}
@end
int main(int argc, const char *argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
Launcher *delegate = [Launcher new];
app.delegate = delegate;
[app run];
}
return 0;
}
EOF
clang -fobjc-arc -framework Cocoa \
main.m \
-o ncview.app/Contents/MacOS/ncview-launcher
この記事では、主にNetCDFファイル側から開く使い方を想定しています。
4. XQuartzとncviewを起動するスクリプトを作る
Finderから起動したアプリでは、ターミナルと同じ環境変数を利用できるとは限りません。
そこで、コマンドのパスを明示し、launchctl getenv DISPLAY で取得できる値を使います。XQuartzの起動直後はまだ接続できない場合があるため、xdpyinfo で確認しながら待ちます。
cat > ncview.app/Contents/Resources/launch-ncview.sh <<'EOF'
#!/bin/zsh
export PATH=/opt/homebrew/bin:/opt/X11/bin:/usr/bin:/bin:/usr/sbin:/sbin
log_dir="$HOME/Library/Logs/ncview-finder"
mkdir -p "$log_dir"
exec >>"$log_dir/launcher.log" 2>&1
/usr/bin/open -a /Applications/Utilities/XQuartz.app
for attempt in {1..30}; do
session_display=$(/bin/launchctl getenv DISPLAY)
[[ -n "$session_display" ]] && export DISPLAY="$session_display"
[[ -z "$DISPLAY" ]] && export DISPLAY=:0
/opt/X11/bin/xdpyinfo >/dev/null 2>&1 && break
sleep 1
done
/opt/X11/bin/xdpyinfo >/dev/null 2>&1 || exit 1
exec /opt/homebrew/bin/ncview "$1"
EOF
chmod +x ncview.app/Contents/Resources/launch-ncview.sh
DISPLAY=:0 は、環境変数が取得できないときの補助的な設定です。すべての環境で接続できることを保証するものではなく、最後に xdpyinfo で接続できなければ終了します。
5. NetCDFを扱うアプリとして登録する
Info.plist にアプリの情報と、扱うファイル形式を記述します。
ここでは .nc、.nc4、.cdf、.netcdf を登録します。ただし、拡張子が一致していても、ファイルの内容がNetCDFとは限りません。特に .cdf は、ほかの形式でも使われるため、関連付けは必要に応じて行ってください。
cat > ncview.app/Contents/Info.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>local.kanon.ncview-finder</string>
<key>CFBundleName</key>
<string>ncview</string>
<key>CFBundleExecutable</key>
<string>ncview-launcher</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSUIElement</key>
<true/>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>NetCDF data</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>LSItemContentTypes</key>
<array>
<string>edu.ucar.unidata.netcdf</string>
</array>
<key>CFBundleTypeExtensions</key>
<array>
<string>nc</string>
<string>nc4</string>
<string>cdf</string>
<string>netcdf</string>
</array>
</dict>
</array>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>edu.ucar.unidata.netcdf</string>
<key>UTTypeDescription</key>
<string>NetCDF data</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>nc</string>
<string>nc4</string>
<string>cdf</string>
<string>netcdf</string>
</array>
<key>public.mime-type</key>
<string>application/x-netcdf</string>
</dict>
</dict>
</array>
</dict>
</plist>
EOF
構文を確認して、ローカル実行用の署名を付けます。
plutil -lint ncview.app/Contents/Info.plist
codesign --force --sign - ncview.app
この署名は ad-hoc署名です。Appleが発行するDeveloper IDによる署名や、Appleの公証とは異なります。
6. アプリを配置し、Finderで関連付ける
Finderで作業フォルダを開きます。
open .
作成した ncview.app を、ユーザー用の ~/Applications フォルダへ移動します。フォルダがなければ、先に作成します。
mkdir -p ~/Applications
同名のアプリがある場合は、上書きする前に既存のアプリを確認してください。
次に、Finderで以下の操作を行います。
-
.ncファイルを1つ選択する。 -
⌘ + Iで「情報を見る」を開く。 - 「このアプリケーションで開く」を展開する。
-
ncview.appを選ぶ。表示されない場合は「その他…」から選択する。 - 「すべてを変更…」をクリックする。
この操作は、選択したファイルだけでなく、同じ種類のファイルに適用されます。Appleの関連付け手順
設定後、.nc ファイルをダブルクリックすると、XQuartz経由でncviewが起動します。
.nc4 なども使う場合は、その拡張子のファイルでも開き方を確認してください。
うまく開かないとき
まず、ターミナルから同じファイルを開けるか確認します。
/opt/homebrew/bin/ncview "/path/to/sample.nc"
ターミナルからも開けない場合は、ncview・XQuartz・入力ファイルの状態を確認します。
ターミナルからは開けるのにFinderから開けない場合は、起動ログを確認します。
tail -n 80 ~/Library/Logs/ncview-finder/launcher.log
今回の起動用スクリプトでは、ncviewの出力やエラーをこのファイルに保存しています。
XQuartzへの接続を確認する場合は、次のコマンドも使えます。
launchctl getenv DISPLAY
/opt/X11/bin/xdpyinfo
なお、この簡易版では、XQuartzへの接続失敗を専用のダイアログでは通知しません。開いても何も起きない場合は、ログとXQuartzの起動状態を確認してください。