مستندات خودکار برای Makefile
این روزها در تمام پروژه هامون از Makefile استفاده می کنیم. ایجاد یک راهنما و مستند ساده برای این فایل میتونه در توسعه اش بسیار موثر باشه.
شرح ماجرا
همه پروژه های ما حاوی یک Makefile هستند تا مراحل نصب ٬ تست و استقرار برای کاربران ساده بشه. اکثر اسامی که برای target ها در نظر گرفته میشن طبق استاندارد های جا افتاده نوشته میشن. برای مثال build
, test
یا run
اما برخی از آنها واقعا نیاز به توضیح اضافه دارند.
برای مثال به این موارد نگاه کنید :
make init
make js
make restart-service
make run-api
make run-dev
شاید در نگاه اول برای خودتان که توسعه دهنده پروژه هستید این target ها معنا دار باشند ولی به دید فردی که برای اولین بار با این پروژه مواجه میشه شاید هیچکدوم این ها دقیق منظورشون رو نشون ندهند. هرچه target های اختصاصی بیشتری در یک پروژه وجود داشته باشه باید توضیحات مناسبی هم برای اون ها در نظر بگیریم.
معمولا چنین کاری در فایل README پروژه انجام میشه:
اما وقتی از CLI استفاده می کنیم ترجیح اینه که از ابزار های self-documentation بهره ببریم. آیا بهتر نیست فقط با تایپ دستور make
لیستی از کلیه دستور ها همراه با توضیحات اون ها لیست بشه ؟ چیزی شبیه به این عکس:
راه حل
شاید الان با خودتون فکر کنید که کار سختی پیش رو داریم ٬ ولی اصلا اینطور نیست. درواقع با ترکیب چند دستور این کار به سادگی انجام میشه.
برای شروع باید برای هر target یک توضیح بنویسیم. مسلما باید از کامنت گذاری استفاده کنید. در Makefile کامنت ها با علامت #
شروع میشن. برای مثال:
# Build the project
build: # info
go build
ولی باید تفاوتی بین نظرات عادی و نظرات مربوط به مستندات ایجاد کنیم. برای این کار پیشنهاد میکنم از دو کارکتر ##
استفاده کنید. برای مثال:
install: ## Install JavaScript dependencies
@echo "Installing dependencies"
@npm install
در اینصورت می توانید هم مستندات خودتون رو داشته باشید هم کامنت های جانبی در کد قرار بدید. بیاید نگاهی به این فایل بکنیم:
JS_DST := nikas/js/embed.min.js nikas/js/embed.dev.js \
nikas/js/count.min.js nikas/js/count.dev.js \
nikas/js/count.dev.js.map nikas/js/embed.dev.js.map
init: ## Install JavaScript modules
npm install -f
nikas/js/%.min.js: $(JS_SRC)
npm run build-prod
nikas/js/%.dev.js: $(JS_SRC)
npm run build-dev
js: $(JS_DST) ## Build the frontend
اگر دقت کنید فقط برای دستورات init
و js
توضیحاتی وجود داره چون فقط همین target ها هستند که به صورت مستقل اجرا میشن.
به باقی موارد internal target گفته میشه. این target ها برای استفاده داخلی هستند و به کاربر نمایش داده نمیشن.
ساخت مستندات
حال با در نظر گرفتن شرایط فوق ٬ توسط چندتا دستور میتونیم خروجی دلنشین و زیبایی داشته باشیم.
ابتدا باید کل خط های این فایل که مورد نظر ما است استخراج بشه. درواقع هر خطی که با یک عبارت و کارکتر :
شروع بشه ٬ در ادامه ##
داشته باشه و کلماتی هم بعدش باشن. برای این کار میتونیم از دستور grep
استفاده کنیم:
grep -E '^[a-zA-Z_-]+:.*?## .*$$' Makefile
این دستور دقیقا توضیحی که بالاتر دادم رو به شما میده:
init: ## Install JavaScript modules
js: $(JS_DST) ## Build the frontend
حال که چنین خروجی داریم با استفاده از awk
میشه دستورات و توضیحات مربوط به اون ها رو از همدیگه جدا کرد و در یک قالب بهتر نمایش داد. به این دستور دقت کنید:
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
در واقع از ##
به عنوان یک delimiter استفاده می کنیم و عنوان از توضیحات جدا میشه. سپس با استفاده از printf
هر قالب خاصی که مد نظرمون باشه به همراه رنگ بندی دلخواه اعمال می کنیم. باید توجه داشته باشید که این دستورات مکمل یکدیگر هستند. پس دستور نهایی ما چیزی شبیه به این خواهد بود:
grep -E '^[a-zA-Z_-]+:.*?## .*$$' Makefile | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
در نهایت یک target برای این دستور به فایل خودتون اضافه کنید:
help: ## Show this help.
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' Makefile | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
حالا با استفاده از دستور make help
میتونید خروجی مستندات رو ببینید.
نکات کنکوری و اضافه کاری
میتونیم دستی به سرش بکشیم و بر اساس حروف الفبا مرتبش کنیم. اینطوری پیدا کردن دستورات و توضیحات اون ها ساده تر میشه:
help: ## Show this help.
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
در این دستور به صورت پیشفرض بین عناوین و توضیحات اندازه ۳۰ ستون فضای خالی قرار دادم. جهت تغییرش کافیه این عدد رو کم و زیاد کنید تا خروجی مطلوب خودتون به دست بیاد. برای مثال :
\033[36m%-20s\033[0m %s\n
\033[36m%-40s\033[0m %s\n
\033[36m%-15s\033[0m %s\n
تا اینجا برای اینکه کاربر بتونه مستندات رو ببینه باید از دستور make help
استفاده کنه. اما میتونیم کار رو ساده تر کنیم با استفاده از DEFAULT_GOAL
یک target پیشفرض تعریف کنیم:
.DEFAULT_GOAL := help
اینطوری فقط کافیه تا دستور make
رو اجرا کرده و مستندات رو ببینیم.
اگر این کد رو مستقیم کپی می کنید یا اصلا فرقی نداره ٬ اگر از Makefile استفاده می کنید توجه کنید که حتما از Tab برای تعیین فاصله استفاده کنید. جهت سادگی میتونید از Editor Config استفاده کنید.
[Makefile]
indent_style = tab
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8
جهت اطلاعات بیشتر به این نوشته مراجعه کنید :