Mac と Windows 両方で動作させるときの注意点
0. 背景と教訓
背景
- Mac で開発していたが、Windows でも動作させたくなった
- そしたらハマった
教訓
- スクリプト系は bash や python でなく極力 node.js でやる
- markdown のファイル名に日本語を使わない
- ファイル open 時の encoding は明示的に指定
特に 1 を守らずハマったのでメモを残しておく。
※ 2 は、濁音/半濁音などで URL encoding や git 周りで苦労するのが想像つくので、避けている (つまりここには解決策は書いてない)
前提
git clone 後にライブラリを入れていること
npm ライブラリ
npm install
Python 関連ライブラリ
venv 作成済であること。
bash
python -m venv .venv
. .venv/Scripts/activate
pip install -r requirements.txt
参考: venvメモ
対応 1. bash にパスが通っていなかった場合、git bash にパスを通す
通常はインストーラで 以下を選んでれば足されるはずなのだが、足されないので手動で足す
- 画面 :
Adjusting your PATH environment
- 項目 :
Git from the command line and also from 3rd-party software
Windows の設定画面からやっても良いが、PowerShell のプロンプトからやる手順はこう。
$gitBashPath = "C:\Program Files\Git\bin"
$oldPath = [Environment]::GetEnvironmentVariable("Path", "User")
$newPath = "$oldPath;$gitBashPath"
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
対応 2. package.json で シェルスクリプトを呼んでいた場合、bash を明示
"scripts": {
"docusaurus": "docusaurus",
"prestart": "tools/preprocess.sh",
"prebuild": "tools/preprocess.sh",
bash から呼ぶ形にする (Windows では shebang は解釈してくれないので。ということだろう)
"scripts": {
"docusaurus": "docusaurus",
"prestart": "bash tools/preprocess.sh",
"prebuild": "bash tools/preprocess.sh",
対応 3. .venv の activate 時の Path が異なっている(なぜ・・)ので、分岐する
前提
- Mac : .venv/bin/activate
- Win : .venv/Scripts/activate (なぜ・・)
こういう差異は venv の利点を損ねていると思うけど・・、まあしょうがないので呼び元のシェルで分岐する
エラーメッセージ
エラーらしいエラーは出ず、以下のように Python
とだけ出て、リターンコード 非0 で失敗する。
$ npm run start
Python
なので、venv が正しく呼べてるか確認のために、バージョン番号も、呼び元シェルで出力しておく。
シェル変更点
#!/usr/bin/env bash
set -e
set -o pipefail
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
# Git Bash / Windows
ACTIVATE=".venv/Scripts/activate"
else
# macOS / Linux
ACTIVATE=".venv/bin/activate"
fi
if [[ -f "$ACTIVATE" ]]; then
. "$ACTIVATE"
else
echo "Error: Cannot find Python virtualenv activate script at $ACTIVATE"
exit 1
fi
# Python 実行確認
echo "Using Python: $(which python)"
python --version
# 以下、もともと呼んでいた Markdown 成形などの前処理 (上のほうが長い・・)
tools/order-dir-category-json.py docs
...
対応 4. shebang に指定するのは python3 でなく python にする
これは venv 使っていれば python
で両対応できるはずなので、そうしておく。
#!/usr/bin/env python3
↓
#!/usr/bin/env python
対応 5. エンコーディングと、改行コードは明示する
前提知識
Python での デフォルト エンコーディング
- Mac/Linux のデフォルト : UTF-8
- Windows のデフォルト : cp932 (Shift-JIS の Microsoft 版みたいなもの)
Python での デフォルト 改行コード
- 読み込み時 : 強制的に '\n' に変換される
- 書き込み時 : OS によって異なる (Win: '\r\n', Mac/Linux: '\n')
エラーメッセージ
エンコーディングでのエラー
UnicodeDecodeError: 'cp932' codec can't decode byte 0x84 in position 23: illegal multibyte sequence
改行コードでの問題
→ git diff したときに気づくことになる ( 行末に ^M
と出る )
修正の例
open 読みモード
with open(path) as f:
↓
with open(path, encoding='utf-8') as f:
open 書きモード
with open(path, 'w') as f:
↓
with open(path, 'w', encoding='utf-8', newline='\n') as f:
read, write
open で明示していれば足りてるはずだが、
必要に応じて read()
, read_text()
, write_text()
も同様に。
デフォルトの encoding の全体設定
- 環境変数で設定できるらしいが、これも環境依存・・・・
- そして、Terminal の出力も変わる・・? それだけ聞くと文字化けなどの二次被害ありそう・・
というわけで、いったん使わず、open()
で指定する方式にする・・。
export PYTHONUTF8=1 # Python 3.7 以降。 入出力と、open() に効く
export PYTHONIOENCODING=utf-8 # Python 3.10 以降。 入出力だけに効く。 open() には効かない
参考:
対応 6. パス区切り文字の吸収
glob
でとってきたディレクトリのパスや、os.path.join()
で作成したパスを、URL のパスに使おうとしてハマった。
→ ここでやったのは、 \\
を /
に変換しただけ
for dirname in [os.path.normpath(x).replace('\\', '/') for x in glob.glob('**/*/', recursive=True)]:
Pathlib で .as_posix()
を使うと良さそうであるが、試してない
from pathlib import Path
dirs = [p.as_posix() for p in Path(".").rglob("*") if p.is_dir()]