این صفحه دربارهی بستههایی است که دیگران در مخزن خودشان نگه میدارند. هرچه در کتابخانهی استاندارد هست همراه مترجم نصب میشود و به salam add نیازی ندارد. بخش زبانی ماجرا، یعنی بسته، فراخوانی و همگانی، در درس هجدهم آمده است.
استفاده از یک بسته
پروژه پوشهای است با یک main.salam و یک salam.toml. دستور salam init پوشهی فعلی را به پروژه تبدیل میکند و فایلهای موجود را دست نمیزند:
$ mkdir app && cd app
$ salam init
Created project 'app':
main.salam
salam.toml
.gitignore
Next steps:
salam run
$ salam add github.com/demo/slug
added github.com/demo/slug v1.1.0
دستور salam add تازهترین انتشار مخزن را پیدا میکند، در ~/.salam/pkg دانلود میکند و در دو فایل ثبتش میکند. salam.toml میگوید شما چه خواستهاید و salam.lock دقیقاً ثبت میکند چه گرفتهاید، یعنی کامیت و یک چکسام؛ برای همین روی هر ماشین همان کد ساخته میشود.
[dependencies]
"github.com/demo/slug" = "v1.1.0"
بستهای که از مخزن میآید با نشانی داخل گیومه وارد میشود. آخرین بخش نشانی نامی میشود که در کد به کار میبرید؛ پس github.com/demo/slug با slug صدا زده میشود:
واردسازی "github.com/demo/slug"
تابع ریشه:
سرچاپ slug.بساز("Hello, World!")
سرچاپ slug.بساز با سقف("Packages in Salam are simple"، 14)
پایان
$ salam run
hello-world
packages-in-sa
اگر دو بسته نام یکسان پیدا کنند، به یکیشان نام دیگری بدهید: import s "github.com/demo/slug" و بعد s.Make(...). برای رسیدن به بستهای در پوشهی یک مخزن، نام پوشه را به نشانی اضافه کنید: import "github.com/owner/repo/sub".
دستورهایی که بیشتر به کار میآیند:
| دستور | کار |
|---|---|
salam add github.com/owner/repo | تازهترین انتشار را اضافه میکند؛ با @v1.2.0 یک تگ مشخص انتخاب میشود |
salam remove github.com/owner/repo | بسته را از salam.toml و salam.lock برمیدارد؛ فایل دانلودشده در انبار میماند |
salam update | همهی بستهها یا فقط بستههای نامبردهشده را به تازهترین انتشار با همان نسخهی اصلی میبرد |
salam deps | هرچه در salam.lock است دانلود و چکسام همه را بررسی میکند؛ بعد از کلونکردن پروژه اجرایش کنید |
salam search words | در کتابخانهی استاندارد و رجیستری جستوجو میکند |
salam install github.com/owner/tool | main.salam یک برنامه را میسازد و در ~/.salam/bin میگذارد |
salam uninstall tool | برنامهی نصبشده را برمیدارد |
فایلهای salam.toml و salam.lock را همراه کدتان کامیت کنید و بستههای دانلودشده را نه. بعد از هر کلون تازه فقط salam deps لازم است:
$ salam deps
github.com/demo/slug v1.1.0
downloaded 1 package(s)
حذف یک بسته، importهای آن را پاک نمیکند و مترجم این را به شما میگوید:
$ salam remove github.com/demo/slug
removed github.com/demo/slug
$ salam run
error[E008]: package 'github.com/demo/slug' is not a dependency of this project; run: salam add github.com/demo/slug
نوشتن یک بسته
بسته یک مخزن گیت است با یک فایل مانیفست و یک فایل ورودی. فایل ورودی نام مخزن را میگیرد؛ مخزن github.com/demo/slug این شکل را دارد:
slug/
salam.toml the manifest
slug.salam the entry file: package slug
slug_test.salam tests, run by salam test
README.md
LICENSE
قاعدهی نام فایلها کوتاه است. برنامه، یعنی چیزی که اجرا میکنید، main.salam دارد و هیچ فایل دیگری هرگز ورودی حساب نمیشود. کتابخانه، یعنی چیزی که پروژههای دیگر وارد میکنند، اصلاً main ندارد؛ ورودیاش <name>.salam است و بستهای که در پوشهای از مخزن است <folder>/<folder>.salam نام دارد؛ همان فایلی که import "github.com/owner/repo/sub" بار میکند. فایلهای دیگر همان بسته کنار فایل ورودی مینشینند و به آن پیوند میخورند، همانطور که در درس هجدهم دیدید.
مانیفست چند خط بیشتر نیست:
[package]
name = "slug"
version = "1.1.0"
salam = ">=0.6.1"
kind = "lib"
[dependencies]
"github.com/owner/other" = "v1.0.0"
nameنام برنامه یا کتابخانه است وversionبرای آدمهاست؛ نسخهای که برای کاربران حساب میشود تگ گیت است.salamقدیمیترین مترجمی است که بسته با آن ساخته میشود. اگر بسته مترجم جدیدتری بخواهد،salam addقبولش نمیکند و میگویدsalam upgradeرا اجرا کنید.kind = "lib"کتابخانه بودن را اعلام میکند؛ برنامه آن را نمینویسد.[dependencies]نیازهای بستهی شما را با همان قالبی فهرست میکند کهsalam addمینویسد. بستههای بستههای شما از مانیفست خودشان پیدا میشوند و اگر دو بسته نسخههای متفاوتی از یک بسته بخواهند، نسخهی تازهتر به کار میرود.
حالا کد. هرچه همگانی (pub) بنویسید چهرهی عمومی بسته و قولی به کاربران است؛ بقیه را در هر انتشار بعدی میتوانید تغییر نام بدهید یا حذف کنید. اینجا Make و MakeMax همگانیاند و is_word نیست. دو خط @en و @fa به هر تابع همگانی یک نام در هر دو زبان میدهند تا برنامههای انگلیسی و فارسی هر دو صدایش بزنند:
هنگام کار، بسته را با یک برنامهی کوچک کنارش امتحان کنید. فراخوانی فایلی از همین پروژه را بار میکند، پس بدون هیچ دانلودی اجرا میشود:
آزمونها در فایلی میروند که نامش به _test.salam ختم شود و تابعهایش test_something نام داشته باشند. دستور salam test همهی این فایلهای پوشه را اجرا میکند، هر کدام در پردازش جدا:
$ salam test
=== RUN test_make
--- PASS: test_make
=== RUN test_make_max
--- PASS: test_make_max
ok slug_test.salam: 2 tests passed
PASS: 1 test files
کاربران فقط نامهای همگانی را میبینند. اگر در پروژهای که به بسته وابسته است، تابع کمکی خصوصی را صدا بزنید (در فایل انگلیسی)، رد میشود:
error[E017]: 'is_word' is not exported by package 'slug' (mark it 'pub')
انتشار بسته
مرحلهی آپلود و دستوری مثل salam publish وجود ندارد. وقتی تگی در یک مخزن عمومی گیت باشد، بسته منتشر شده است، چون salam add همین را میخواند. روند کار:
- بسته را در مخزنی همنام خودش بگذارید و فایل ورودی و
salam.tomlرا در سطح بالای مخزن (یا با چیدمان پوشهای بالا) قرار دهید. - بررسی کنید:
salam testموفق باشد وsalam check slug.salamخطایی نشان ندهد. - یک
README.mdبنویسید که طرز افزودن و وارد کردن بسته و یک مثال کوتاه را نشان بدهد و یک فایلLICENSEاضافه کنید. بدون مجوز، هیچکس اجازه ندارد از کدتان استفاده کند. - کامیت کنید، انتشار را با تگ
vMAJOR.MINOR.PATCHبرچسب بزنید و تگ را push کنید.
$ git tag v1.1.0
$ git push origin main v1.1.0
از این لحظه هر کسی میتواند salam add github.com/owner/slug را بزند. پیش از اعلام بسته، خودتان در یک پروژهی خالی امتحانش کنید: دقیقاً همان مسیری است که کاربرانتان میروند و نبودِ فایل ورودی را همان لحظه نشان میدهد.
بستههای gitlab.com و codeberg.org هم کار میکنند و اگر گیت نصب باشد، هر میزبان دیگری هم. مخزنهای خصوصی با اعتبارنامههایی که گیت از قبل دارد کار میکنند.
پیدا شدن بسته
دستور salam search فایل registry/index.toml را در مخزن سلام میخواند؛ فهرستی که با pull request بهروز میشود. ثبت در آن اختیاری است، چون salam add برای هر مخزن عمومی کار میکند، ولی کمک میکند دیگران بسته را با کلمههایش پیدا کنند:
[[package]]
name = "github.com/owner/slug"
description = "Turn text into URL slugs"
tags = ["text", "url"]
یک pull request باز کنید که فقط یک ورودی مثل بالا به فایل اضافه کند. مخزن باید salam.toml و فایل ورودی داشته باشد و انتشارهایش با تگ vX.Y.Z باشند. بعد از ادغام، salam search slug نام و توضیح را چاپ میکند.
همان مخزن فایل registry/sums.txt را هم نگه میدارد: فهرستی بازبینیشده از چکسامها، با یک خط module@version sum برای هر انتشار. دانلودی که با خط منتشرشده فرق کند رد میشود. داخل پروژهای که از بستهی شما استفاده میکند، salam deps sums خطهایی را چاپ میکند که در pull request پیشنهاد میدهید:
$ salam deps sums
github.com/demo/[email protected] sha256:f20515bfd08073aebe3d95568695089f8bc7264437e02bad6d87e8b094b9efde
نسخهها
هر انتشار یک تگ گیت به شکل v1.2.3 است. معنای همیشگی را رعایت کنید: وصله (v1.2.4) خطا را رفع میکند، نسخهی فرعی (v1.3.0) چیزی اضافه میکند بیآنکه کد قدیمی را بشکند، و نسخهی اصلی (v2.0.0) ممکن است بشکند. وقتی کسی تگی را دانلود کرده، جابهجا کردن آن امن نیست، چون چکسام در salam.lock او دیگر نمیخواند. بهجایش نسخهی تازهای منتشر کنید.
نسخه در salam.toml به چهار شکل نوشته میشود:
| نوشته | معنی |
|---|---|
"v1.2.0" | دقیقاً همان تگ |
"^1.2" | هر 1.x از 1.2.0 به بالا (برای 0.x، همان نسخهی فرعی) |
"~1.2" | هر 1.2.x |
">=1.2" | 1.2.0 یا هر نسخهی جدیدتر |
دستور salam add github.com/owner/repo@^1.2 بازه را مینویسد و تازهترین انتشار درون آن را قفل میکند. فایل قفل همیشه یک نسخهی دقیق دارد، پس ساختها تا وقتی salam update نزدهاید تکرارپذیر میمانند.
$ salam add github.com/demo/[email protected]
added github.com/demo/slug v1.0.0
$ salam update
updated github.com/demo/slug v1.0.0 -> v1.1.0
دستور salam update خودش هرگز به نسخهی اصلی بعدی نمیرود. وجودش را خبر میدهد و تصمیم را به شما میسپارد:
$ salam update
github.com/demo/slug v2.0.0 is out; it may break your code, move with: salam update github.com/demo/slug@latest
github.com/demo/slug is up to date (v1.1.0)
$ salam update github.com/demo/slug@latest
updated github.com/demo/slug v1.1.0 -> v2.0.0
مخزنی که هیچ تگی ندارد هم قابل افزودن است. سلام در این حالت کامیت دقیق را با یک نسخهی مجازی مثل v0.0.0-8177964855e1 ثبت میکند و salam update آن را به تازهترین کامیت میبرد. وقتی بسته هنوز نوپاست این کار راحت است، و دلیل خوبی است که انتشار اول را زود تگ بزنید.
برای نویسنده، نسخهی اصلی تازه یعنی نشانی تازهی وارد کردن. import "github.com/owner/repo/v2" فقط تگهای v2 را میپذیرد و یک برنامه میتواند v1 و v2 را کنار هم داشته باشد. کد v2 میتواند در پوشهی v2/ یا در ریشهی مخزن باشد؛ برای استفاده در کنار v1 ورودیاش repo2.salam نام میگیرد و package repo2 اعلام میکند.
وقتی مشکلی پیش میآید
| پیام | دلیل و کار درست |
|---|---|
package '...' has no entry file (looked for '.../argon.salam') | مخزن از چیدمان بخش نوشتن یک بسته پیروی نمیکند: import "github.com/owner/name" فایل name.salam را در سطح بالای مخزن بار میکند. salam add با این حال موفق میشود، چون فقط دانلود میکند. از نویسنده بخواهید فایل ورودی را اضافه کند، یا فایلها را همانطور که README خود بسته میگوید با فراخوانی به کار ببرید |
package '...' is not a dependency of this project; run: salam add ... | این import در salam.toml نیست. دستوری را که چاپ شده اجرا کنید، یا از پوشهی خود پروژه کار کنید |
'name' is not exported by package '...' (mark it 'pub') | بسته آن نام را خصوصی نگه داشته است. از رابط همگانیاش استفاده کنید، یا از نویسنده بخواهید آن را همگانی کند |
salam: cannot list the versions of https://github.com/... | نشانی غلط نوشته شده، مخزن خصوصی است و اعتبارنامه ندارید، یا گیت به میزبان نمیرسد |
salam: git could not fetch v9.0.0 from ... | چنین تگی وجود ندارد. تگهای مخزن را ببینید، یا نسخه را ننویسید تا تازهترین گرفته شود |
no main.salam in '...': a project's entry file must be named main.salam | salam build یا salam run را بیرون از پروژه زدهاید. با salam init پروژه بسازید |
'...' has no main.salam, so there is no program to install | salam install برای برنامههاست. کتابخانه را با salam add به کار ببرید |
needs Salam X or newer; run: salam upgrade | خط salam در مانیفست بسته، مترجم جدیدتری از مترجم شما میخواهد |
چند نکتهی دیگر که بعضی غافلگیریها را توضیح میدهد:
- تگی که بعد از انتشار جابهجا شده باشد چکسام دیگری میدهد و دستور بهجای ساختن کد متفاوت، متوقف میشود. اگر نسخهی تازه درست است، خطش را از
~/.salam/pkg/sums.txtپاک کنید. - اگر گیت روی ماشین نباشد، بستههای گیتهاب، گیتلب و کدبرگ بهصورت آرشیو دانلود میشوند.
GITHUB_TOKENسقف درخواست گیتهاب را برای فهرست تگها بالا میبرد وSALAM_NO_GIT=1مسیر آرشیو را اجباری میکند. SALAM_PKGپوشهی دانلودها را عوض میکند وsalam deps cleanآن را خالی میکند.- اگر به نظر میرسد ساخت از کد قدیمی استفاده میکند، پوشهی
.salam-buildپروژه را پاک کنید و دوباره بسازید.
دنبال نمونه میگردید؟ بستههای کتابخانهی استاندارد دقیقاً به همین شکل نوشته شدهاند: یک پوشه برای هر بسته و فایل ورودی همنام آن. در مرجع کتابخانه ببینیدشان.