スライドショー立ち上げ:
# http://localhost:8000
make slideshow
# portを変更 (http://localhost:XXXX)
make slideshow PORT=<XXXX>
サンプルプロジェクト用ディレクトリ生成:
# 全部生成
make
# or
make all
# pythonサンプルのみ
make python-example
# goサンプルのみ
make go-example
root = true | |
[*] | |
end_of_line = lf | |
insert_final_newline = true | |
[*.md] | |
trim_trailing_whitespace = false |
python-example | |
go-example |
スライドショー立ち上げ:
# http://localhost:8000
make slideshow
# portを変更 (http://localhost:XXXX)
make slideshow PORT=<XXXX>
サンプルプロジェクト用ディレクトリ生成:
# 全部生成
make
# or
make all
# pythonサンプルのみ
make python-example
# goサンプルのみ
make go-example
.venv | |
*.py[cod] | |
__pycache__/ | |
*$py.class |
MAKEFLAGS += --warn-undefined-variables | |
SHELL := /bin/bash | |
.SHELLFLAGS := -eu -o pipefail -c | |
.DEFAULT_GOAL := build | |
.PHONY: build run clean help | |
go-example: go.mod main.go | |
go build | |
build: go-example ## build binary file | |
run: ## run app | |
@go run main.go | |
clean: ## cleanup binary | |
rm go-example | |
help: ## Print this help | |
@echo 'Usage: make [target]' | |
@echo '' | |
@echo 'Targets:' | |
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) |
module go-example | |
go 1.20 |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>GNU Make as TaskRunner</title> | |
<meta charset="utf-8"> | |
<style> | |
@page { | |
size: 1210px 681px; | |
margin: 0; | |
} | |
@media print { | |
.remark-slide-scaler { | |
width: 100% !important; | |
height: 100% !important; | |
transform: scale(1) !important; | |
top: 0 !important; | |
left: 0 !important; | |
} | |
} | |
body { font-family: sans-serif; } | |
h1, h2, h3 { | |
font-weight: normal; | |
} | |
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; } | |
</style> | |
</head> | |
<body> | |
<textarea id="source"> | |
class: center, middle | |
# Title | |
--- | |
# Agenda | |
1. Introduction | |
2. Deep-dive | |
3. ... | |
--- | |
# Introduction | |
</textarea> | |
<script src="https://remarkjs.com/downloads/remark-latest.min.js"> | |
</script> | |
<script> | |
var slideshow = remark.create({ | |
sourceUrl: 'slides.md', | |
}); | |
</script> | |
</body> | |
</html> |
package main | |
import "fmt" | |
func main() { | |
fmt.Println("Hello, World!") | |
} |
""" | |
FastAPI sample-app | |
original: https://fastapi.tiangolo.com/ja/tutorial/first-steps/ | |
""" | |
from fastapi import FastAPI | |
app = FastAPI() | |
@app.get("/") | |
async def root(): | |
return {"message": "Hello World"} |
MAKEFLAGS += --warn-undefined-variables | |
SHELL := /bin/bash | |
.SHELLFLAGS := -eu -o pipefail -c | |
.DEFAULT_GOAL := all | |
# 作成するサンプルプロジェクト | |
PYTHON_EXAMPLE := "python-example" | |
GO_EXAMPLE := "go-example" | |
# all targets are phony | |
.PHONY: all | |
all: python-example go-example | |
python-example: ## create python-example | |
@echo 'Start to create $@' | |
@mkdir $(PYTHON_EXAMPLE) | |
@cp python-example.mk $(PYTHON_EXAMPLE)/Makefile | |
@cp python-example.md $(PYTHON_EXAMPLE)/README.md | |
@cp pre-commit-config-python-example.yaml $(PYTHON_EXAMPLE)/.pre-commit-config.yaml | |
@cp gitignore_python-example $(PYTHON_EXAMPLE)/.gitignore | |
@cp main.py $(PYTHON_EXAMPLE) | |
@cp requirements.txt $(PYTHON_EXAMPLE) | |
@echo 'Finished to create $@' | |
go-example: ## create go-example | |
@echo 'Start to create $@' | |
@mkdir $(GO_EXAMPLE) | |
@cp go-example.mk $(GO_EXAMPLE)/Makefile | |
@cp go-example.md $(GO_EXAMPLE)/README.md | |
@cp main.go $(GO_EXAMPLE) | |
@cp go.mod $(GO_EXAMPLE) | |
@echo 'Finished to create $@' | |
# taskB: ## executes task B | |
# @echo 'Starting $@' | |
# sleep 1 | |
# @echo 'Finished $@' | |
clean: | |
rm -rf $(PYTHON_EXAMPLE) | |
rm -rf $(GO_EXAMPLE) | |
help: ## Print this help | |
@echo 'Usage: make [target]' | |
@echo '' | |
@echo 'Targets:' | |
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | |
PORT = 8000 | |
slideshow: ## start localserver for slideshow: ex)make slideshow PORT=xxxx | |
@python3 -m http.server --bind 127.0.0.1 ${PORT} |
# example from https://pre-commit.com/#2-add-a-pre-commit-configuration | |
repos: | |
- repo: https://github.com/pre-commit/pre-commit-hooks | |
rev: v2.3.0 | |
hooks: | |
- id: check-yaml | |
- id: end-of-file-fixer | |
- id: trailing-whitespace | |
- repo: https://github.com/psf/black | |
rev: 22.10.0 | |
hooks: | |
- id: black |
注意:
python3 -m pip install -U --user pre-commit
など--user
オプション付きでも仮想環境外でのpipの使用はNGらしいので、
代わりにpipx install pre-commit
などとするポイント:
.venv
ディレクトリが無いとき)に実行される、といった形で無駄なタスクが走らないようにしている主な操作:
make setup
make dev
setup
を行っていない場合は先に自動で実行するmake start
setup
を行っていない場合は先に自動で実行するmake clean
__pycache__
など)および、仮想環境を削除してクリーンアップするMAKEFLAGS += --warn-undefined-variables | |
SHELL := /bin/bash | |
.SHELLFLAGS := -eu -o pipefail -c | |
.DEFAULT_GOAL := setup | |
PYTHON = python3 | |
VENV = .venv | |
# all targets are phony | |
# .PHONY: $(shell egrep -o ^[a-zA-Z_-]+: $(MAKEFILE_LIST) | sed 's/://') | |
.PHONY: setup dev start clean help | |
.git: | |
[[ ! -d .git ]] && git init | |
.git/hooks/pre-commit: .git | |
[[ -d .git ]] && pre-commit install | |
$(VENV): requirements.txt | |
$(PYTHON) -m venv $(VENV) | |
$(VENV)/bin/python3 -m pip install --upgrade -r requirements.txt | |
@touch $(VENV) | |
setup: $(VENV) .git .git/hooks/pre-commit ## setup project | |
dev: setup ## start FastAPI app (with reload) | |
source $(VENV)/bin/activate; uvicorn main:app --reload | |
start: setup ## start FaastAPI app | |
source $(VENV)/bin/activate; uvicorn main:app | |
clean: ## cleanup project | |
rm -rf $(VENV) | |
find . -type f -name *.pyc -delete | |
find . -type d -name __pycache__ -delete | |
help: ## Print this help | |
@echo 'Usage: make [target]' | |
@echo '' | |
@echo 'Targets:' | |
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) |
# install fastapi[all] & uvicorn[default] | |
anyio==3.6.2 | |
certifi==2023.5.7 | |
click==8.1.3 | |
dnspython==2.3.0 | |
email-validator==2.0.0.post2 | |
fastapi==0.95.1 | |
h11==0.14.0 | |
httpcore==0.17.0 | |
httptools==0.5.0 | |
httpx==0.24.0 | |
idna==3.4 | |
itsdangerous==2.1.2 | |
Jinja2==3.1.2 | |
MarkupSafe==2.1.2 | |
orjson==3.8.11 | |
pydantic==1.10.7 | |
python-dotenv==1.0.0 | |
python-multipart==0.0.6 | |
PyYAML==6.0 | |
sniffio==1.3.0 | |
starlette==0.26.1 | |
typing_extensions==4.5.0 | |
ujson==5.7.0 | |
uvicorn==0.22.0 | |
uvloop==0.17.0 | |
watchfiles==0.19.0 | |
websockets==11.0.3 |
class: center, middle
プロジェクトのセットアップ、ビルド、実行、デプロイとしった開発作業のライフサイクル中で頻繁、 あるいは確実に行う操作をスクリプト化しておいてポータビリティ性を確保することは開発の効率化やミスの低減につなげることになり、 そのためにいわゆるタスクランナーと言われるツールの活用が有効である。
nodejsのnpm-scriptsなど言語・ランタイムに初めからタスクランナー機能が組み込まれていれば良いが、 一般的にはタスクランナー機能を別途用意する必要があり、その選択肢のの一つとしてGNU make(Makefile)の活用が挙げられる。
そもそもデフォルトで入っていることが多い。
一方、Dockerイメージなどパッケージが削られているケースでは入っていないケースもあるが、そのような場合でも
# debian系
sudo apt install make
# redhat系
sudo dnf install make
など、ディストリビューション標準のパッケージマネージャーからほぼ確実にインストールできる
Makefile
、あるいは拡張子.mk
のテキストファイルを作成し、
そのファイルが置かれているディレクトリでmake
コマンドを実行して使う
文法などの基本事項は「参考」で挙げているリンクなどを参照のこと
今回は適当な例を2つ作成している(makeコマンドで生成できる):
make
に限った話ではないが、)
あまりにも自由にタスク・コマンドを作っていくと本来想定されるmakeの使い方から大きく外れて収集がつかなくなる可能性がありそうclass: center, middle