| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 |
- #!/usr/bin/env python3
- """将 dotenv 转成 docker run --env-file 的字面值格式,不打印凭证。"""
- import argparse
- import os
- from pathlib import Path
- import re
- import tempfile
- from dotenv import dotenv_values
- def export(source, target):
- source, target = Path(source).resolve(strict=True), Path(target).absolute()
- if source == target.resolve():
- raise ValueError('导出文件不能覆盖原 .env')
- rows = []
- for key, value in dotenv_values(source).items():
- if not re.fullmatch(r'[A-Za-z_][A-Za-z0-9_]*', key):
- raise ValueError('存在 Docker 不支持的环境变量名称')
- if value is None:
- continue
- if any(char in value for char in '\r\n\x00'):
- raise ValueError(f'{key} 含有 Docker env-file 不支持的换行或空字符')
- rows.append(key + '=' + value + '\n')
- target.parent.mkdir(parents=True, exist_ok=True)
- partial = None
- try:
- # 临时文件权限0600;写完后原子替换,保留原 .env,不输出任何配置值。
- with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', dir=target.parent,
- prefix='.docker-env-', delete=False) as stream:
- partial = Path(stream.name)
- stream.writelines(rows)
- os.replace(partial, target)
- finally:
- if partial is not None:
- partial.unlink(missing_ok=True)
- return len(rows)
- if __name__ == '__main__':
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument('source', nargs='?', default='.env')
- parser.add_argument('target', nargs='?', default='.env.docker')
- args = parser.parse_args()
- try:
- count = export(args.source, args.target)
- except (OSError, ValueError) as exc:
- parser.exit(1, f'转换失败:{exc}\n')
- print(f'已导出 {count} 个配置项,文件权限0600;未输出配置值。')
|