ビットの海

ゆるふわソフトウェアエンジニアしゃぜのブログ

Pandoc と LuaLaTeX で、Markdown から日本語 PDF を生成

インストール&設定

Pandoc と basictex(Mactexディストリビューション)をインストール

brew install pandoc
brew install basictex

tlmgr (tex live のマネージャ)で、設定を行う

# tlmgr の path を通す
export PATH=$PATH:/usr/local/texlive/2024basic/bin/universal-darwin
# パッケージアップデート
sudo tlmgr update --self --all

# A4サイズ指定
sudo tlmgr paper a4

# 日本語対応のLaTeXパッケージコレクションをインストール
sudo tlmgr install collection-langjapanese

# LuaLaTeXでの数学式の処理を改善するパッケージのインストール
sudo tlmgr install lualatex-math

# Type 1 Computer Modernフォントを使用可能にするパッケージをインストール
sudo tlmgr install type1cm

# 選択的に合字(ligature)を抑制するパッケージをインストール
sudo tlmgr install selnolig

PDF 生成

pandoc sample.md -o sample.pdf --pdf-engine=lualatex -V documentclass=bxjsarticle -V classoption=pandoc

-V documentclass=bxjsarticle

  • LaTeXで使用するドキュメントクラスを指定している。
  • bxjsarticleは、日本語対応のLaTeXクラスで、標準的なarticleクラスを拡張したもの。
  • 日本語の文字コードや行間設定を自動調整して、日本語文書に適したレイアウトを提供。

参考にしました

Pandocの比較的簡単なインストール方法 #Markdown - Qiita

MacでPandoc+LaTeXを使って日本語を含むjmarkdownファイルをpdfファイルに変換する

今年も3人育児しながらエンジニアやってる

はじめに

自己紹介

  • 都内IT企業でデータエンジニアしてるアラフォー男性
  • 子ども3人(7歳、4歳、0歳)

さて

今年もいろいろありました。TOPIC3つでお届けします。

TOPIC 1 : 3人目が生まれる

2024年2月に3人目が誕生しました。生まれるまでにもドタバタあって、生まれてからもドタバタしているんですが、なんとかみんな元気に生きています(秋〜冬にかけてエンドレス風邪が蔓延していますが....)

いやーしかし、2人育てているとはいえ、結構忘れているものでして、久しぶりに「赤ちゃん」という存在と向き合っております。

TOPIC 2 : 上の子が小学校入学

個人的にはこれが結構大きいトピックでして。やっぱり保育園とはほんと全然違うんですよね〜。いろいろ書きたい事はあるんですが、まぁおいおいココでも書いていくと思います。

そして、多少小1の壁みたいなものもありました。が、今はなんとか(文句を言いながらも)学校に通ってますね。

TOPIC 3 : 去年はじめたテック業界子育てDiscord が1周年

shase428.hatenablog.jp

去年書いたこれですね。ゆるゆる平和にやってます。まぁXも殺伐としてるところもあるので、ちょっとだけクローズドな場所ということで...。

今思うエンジニアと子育て

子育て側から

2021年に書いた Hackしないふつーの育児 - ビットの海 とあまり変わってないんですが、育児は結局衣食住を整えるベースがあって、まぁその上に、何かオプション乗せましょうか、みたいな感じだと日々感じています。

小学生が一人一台タブレットを支給され、「ZOOM授業の日」なんてものがあるデジタルな世の中ではありますが、育児でやることの本質みたいなものは昔も今も変わらんのでしょうね。

エンジニア側から

40を過ぎたというのもあって、キャリアに悩むみたいなのもすっかり減りました。日々知らんこと多いな〜つらっ、みたいな気持ちはありますけど、好奇心は相変わらずあるし、時間はないけど好奇心と健康があればなんとか生き残れるかも?みたいな気持ちです。

おわりに

毎年カレンダーを立てて頂いて感謝しています。みなさん今年もお疲れ様でした。来年も仕事と育児を頑張って行きましょう!

ここ3年ぐらいの仕事を雑に振り返っておくメモ

なんかもう忘れてしまうので...

2022年

1Q

  • 当時の職場の退職準備
  • サイエンティストの人がモデル作って、APIGCPのインフラ環境を俺が作るというプロジェクトをやっていた。
  • APIは、Python / FastAPI でちょろっとつくった。

2Q

  • 4月いっぱいで当時の職場を退職
  • 5月から新しい職場(現職)にJoin
  • とりあえず、Jenkins と Embulk / DigDag ベースの ETLがやばいという話があって、それの改善をし始めた。
  • Airflow ベースの ETLの仕組みに順次切替えを開始した。

3Q

  • AirflowベースのETLの仕組みに大方切替えができた。
  • このへんから、古い仕組みを順次退役させていく仕事が始まる。

4Q

  • 仕事としては直近の3Qとあまり変わらない。
  • 雑多なデータの仕事をしている。

2023年

1Q

  • なんか調整さんみたいな仕事が多かった気がする。
  • 仕組みとプロジェクトの交通整理というか。
  • あんまりエンジニアしてなかったのでは...。
  • 相変わらず古いパイプラインの廃止を順次している。

2Q

  • 雑多なデータの仕事をしている。
  • 2024年にもつながる某部署向けAPI接続プロジェクトを交通整理しながら進行中。
  • 相変わらず古いパイプラインの廃止を順次していた気がする。

3Q

  • 雑多なデータの仕事をしている。
  • なんか社内のChatGPTハッカソンイベントとかやってた。
  • インターン(高校生)受け入れて、ドタバタ
  • 相変わらず古いパイプラインの廃止を順次していた気がする。

4Q

  • 他の部署を巻き込んだ某レガシー廃止プロジェクトの立ち上げ
  • 雑多なデータの仕事をしている。
  • 相変わらず古いパイプラインの廃止を順次していた気がする。

2024年

1Q

  • 雑多なデータの仕事をしている。
  • 相変わらず古いパイプラインの廃止を順次していた気がする。
  • 相変わらず調整ごとが多い。

2Q

  • 4月まるまる育休。
  • 相変わらず古いパイプラインの廃止を順次していた気がする。
  • 相変わらず調整ごとが多い。
  • GCP の CCOE っぽい仕事を多少していたかもしれない。

3Q

  • 雑多なデータの仕事をしている。
  • 相変わらず古いパイプラインの廃止を順次していた気がする。
  • 相変わらず調整ごとが多い。

4Q

  • 某部署向けAPI接続プロジェクトのマイグレーションで多少Pythonをあれこれ。
  • プロダクトのマイグレーションに伴うデータ基盤の切り替え祭り
  • 雑多なデータの仕事をしている。
  • 相変わらず古いパイプラインの廃止を順次していた気がする、やっと終わりそう。
  • 相変わらず調整ごとが多い。

AWS DMSでハマった件3つ

問題1 : 同一時刻のトランザクションで、どの操作がどの順番で行われたのかわからなくなる

解決方法

AR_H_CHANGE_SEQ を使う

参考

aws.amazon.com

問題2 : MySQLをソースとして、CDC中にパーティショニングテーブルの操作が行われるとCDCがストップする

解決方法

エンドポイント設定に、skipTableSuspensionForPartitionDdl を使う

参考

docs.aws.amazon.com

問題3 : Aurora の MySQL 互換インスタンスをソースとすると、リードレプリカのエンドポイントからCDCできない

解決方法

とくにないので、Writerのエンドポイント使うしかない(辛い)

参考

repost.aws

DuckDB cli で parquet ファイルを編集しよう

shase428.hatenablog.jp

以前、parquet-cli のことを書いたけど、今回は DuckDB なんだ。

DuckDB はこれね

duckdb.org

インストール

brew install duckdb

でOK

parquet ファイルを Load して編集して、Export する流れ

$ duckdb 

コマンドラインを起動

ちなみに、select するだけなら、以下でOK

select * from '/path/to/foobar.parquet'

update とかしたいのであれば、table 化する必要がある

1. テーブル化

CREATE TABLE tmp_t AS
    SELECT * FROM read_parquet('/path/to/foobar.parquet');

2. 作成したテーブルに対して Update

update tmp_t set value = 'small' where id < 100;

みたいな感じ

3. parquetファイルとして export

tmp_t に反映されているので、これを parquet ファイルとして書き出せばよい

$ COPY (SELECT * FROM tmp_t) TO '/path/to/foobar2.parquet' (FORMAT PARQUET);

その他便利なこと

DESCRIBE TABLE

DESCRIBE TABLE '/path/to/foobar.parquet'

SELECT 結果の csv 出力

COPY (select *  from tmp_t) TO 'output.csv' (HEADER, DELIMITER ',');

まぁ、マニュアルみれば全部書いてるけどね。

duckdb.org

オブジェクトストレージに直接アクセスできるのとか優秀すぎ

duckdb.org

Pythonコーディング用にneovimを最低限整える(2024年夏)

さて前回のコレから5年が経過しています...

shase428.hatenablog.jp

shase428.hatenablog.jp

コンセプト

  • とりあえずこれくらいやればLSP動くよ〜という紹介
  • 脱 coc.nvim
  • LSは手動で管理するので、mason.nvim みたいなのは使わない
  • Python の LSP を最低限の設定で動かして、Ruff で Lint/Format する

環境

brew install nvim したもの

$ nvim -version
NVIM v0.10.0
Build type: Release
LuaJIT 2.1.1716656478

今回登場するプラグイン

プラグイン管理

folke/lazy.nvim でいきます。 Mac の場合は、~/.local/share/nvim/lazy 配下に git clone した plugin が置かれます。

vim.loader.enable()
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
  "neovim/nvim-lspconfig",
  "hrsh7th/nvim-cmp",
  "hrsh7th/cmp-nvim-lsp",
  "hrsh7th/cmp-buffer",
  "hrsh7th/cmp-path",
  "saadparwaiz1/cmp_luasnip",
  "L3MON4D3/LuaSnip",
  "dense-analysis/ale",
})

LSPと補完の設定

なんでも良いんですけど、惰性で、jedi-language-server を使っています。

コンセプト

  • 各プロジェクトの .venv 配下を見せたい
  • $PROJECT_VENV を direnv で制御している
    • Pythonプロジェクトのrootに、以下のような .envrc を置いておく
export VENV_DIR=".venv"
export PROJECT_ROOT=`pwd`
export PROJECT_VENV=${PROJECT_ROOT}/${VENV_DIR}
export PATH=${PROJECT_VENV}/bin:$PATH

init.lua

-- lspのハンドラーに設定
capabilities = require("cmp_nvim_lsp").default_capabilities()

-- lspの設定後に追加
vim.opt.completeopt = "menu,menuone,noselect"

local cmp = require"cmp"
cmp.setup({
  snippet = {
    expand = function(args)
      require("luasnip").lsp_expand(args.body)
    end,
  },
  mapping = cmp.mapping.preset.insert({
    ["<C-p>"] = cmp.mapping.select_prev_item(),
    ["<C-n>"] = cmp.mapping.select_next_item(),
    ["<C-d>"] = cmp.mapping.scroll_docs(-4),
    ["<C-f>"] = cmp.mapping.scroll_docs(4),
    ["<C-Space>"] = cmp.mapping.complete(),
    ["<C-e>"] = cmp.mapping.close(),
    ["<CR>"] = cmp.mapping.confirm({ select = true }),
  }),
  sources = cmp.config.sources({
    { name = "nvim_lsp" },
    { name = "luasnip" },
  }, {
    { name = "buffer" },
  })
})

-- python の path の切り替え
local function expand(str)
  return vim.fn.expand(str)
end

local project_venv = expand('$PROJECT_VENV') .. '/bin/python3'

if vim.fn.executable(project_venv) == 1 then
  vim.g.python3_host_prog = project_venv
else
  local home_python = expand('$HOME/nvim-python/.venv/bin/python3')
  vim.g.python3_host_prog = home_python
end

-- lspconfig の有効化
require'lspconfig'.jedi_language_server.setup{}

pip

  • neovim を忘れずに
  • これは各プロジェクトの venv でのpipです
$ pip install jedi-language-server neovim

動作イメージ

Linter / Formatter

コンセプト

  • ruff で良いかなと
  • ただ、none-ls みたいなやつに、linter / formatter を統合するのにちょっと抵抗感があって、ale にしています

init.lua

-- ale
vim.g.ale_linters = {
    python = {'ruff'},
}

vim.g.ale_fixers = {
    python = {'ruff'},
}

vim.g.ale_fix_on_save = 1

pip

  • これは各プロジェクトの venv でのpipです
pip install ruff

動作イメージ

こんな感じで怒られる&保存するとfixされる

今回のinit.luaの全体

  • 今回紹介したプラグイン周りの全体像はこんな感じ。
  • 見ての通り最低限なので、ぼちぼち育てていきます。
vim.cmd('let $LANG = "en_US.UTF-8"')

vim.loader.enable()
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git",
    "clone",
    "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", -- latest stable release
    lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
  "neovim/nvim-lspconfig",
  "hrsh7th/nvim-cmp",
  "hrsh7th/cmp-nvim-lsp",
  "hrsh7th/cmp-buffer",
  "hrsh7th/cmp-path",
  "saadparwaiz1/cmp_luasnip",
  "L3MON4D3/LuaSnip",
  "dense-analysis/ale",
})

-- lspのハンドラーに設定
capabilities = require("cmp_nvim_lsp").default_capabilities()

-- lspの設定後に追加
vim.opt.completeopt = "menu,menuone,noselect"

local cmp = require"cmp"
cmp.setup({
  snippet = {
    expand = function(args)
      require("luasnip").lsp_expand(args.body)
    end,
  },
  mapping = cmp.mapping.preset.insert({
    ["<C-p>"] = cmp.mapping.select_prev_item(),
    ["<C-n>"] = cmp.mapping.select_next_item(),
    ["<C-d>"] = cmp.mapping.scroll_docs(-4),
    ["<C-f>"] = cmp.mapping.scroll_docs(4),
    ["<C-Space>"] = cmp.mapping.complete(),
    ["<C-e>"] = cmp.mapping.close(),
    ["<CR>"] = cmp.mapping.confirm({ select = true }),
  }),
  sources = cmp.config.sources({
    { name = "nvim_lsp" },
    { name = "luasnip" },
  }, {
    { name = "buffer" },
  })
})

-- python の path の切り替え
local function expand(str)
  return vim.fn.expand(str)
end

local project_venv = expand('$PROJECT_VENV') .. '/bin/python3'

if vim.fn.executable(project_venv) == 1 then
  vim.g.python3_host_prog = project_venv
else
  local home_python = expand('$HOME/nvim-python/.venv/bin/python3')
  vim.g.python3_host_prog = home_python
end

-- lspconfig の有効化
require'lspconfig'.jedi_language_server.setup{}

-- ale
vim.g.ale_linters = {
    python = {'ruff'},
}

vim.g.ale_fixers = {
    python = {'ruff'},
}

vim.g.ale_fix_on_save = 1

参考にしました

zenn.dev

qiita.com

zenn.dev

gcloud で service account で auth してコマンド使えるようにするまで

いつも忘れるので...

1. credentials の json で auth する

gcloud auth activate-service-account \
    foo@foo-project.iam.gserviceaccount.com \
    --key-file /path/foo-project-1234.json \
    --project foo-project

2. auth されてるのを確認する

 gcloud auth list

切り替えは、gcloud config set account ACCOUNT

3. 新しい configuration つくって set して activate

gcloud config configurations create foo-user
gcloud config set project foo-project // project set
gcloud config set account foo@example.com // account set
gcloud config configurations activate foo-user

確認は gcloud config configurations list