راهنمای سبک ساخت

قالب بندی فایل BUILD از همان رویکرد Go پیروی می کند، جایی که یک ابزار استاندارد از اکثر مسائل قالب بندی مراقبت می کند. Buildifier ابزاری است که کد منبع را به سبک استاندارد تجزیه و منتشر می کند. بنابراین هر فایل BUILD به همان روش خودکار قالب‌بندی می‌شود، که باعث می‌شود قالب‌بندی در طول بررسی کد مشکلی نداشته باشد. همچنین درک، ویرایش و تولید فایل های BUILD را برای ابزارها آسان تر می کند.

قالب بندی فایل BUILD باید با خروجی سازنده buildifier داشته باشد.

نمونه قالب بندی

# Test code implementing the Foo controller.
package(default_testonly = True)

py_test(
    name = "foo_test",
    srcs = glob(["*.py"]),
    data = [
        "//data/production/foo:startfoo",
        "//foo",
        "//third_party/java/jdk:jdk-k8",
    ],
    flaky = True,
    deps = [
        ":check_bar_lib",
        ":foo_data_check",
        ":pick_foo_port",
        "//pyglib",
        "//testing/pybase",
    ],
)

ساختار فایل

توصیه : از ترتیب زیر استفاده کنید (هر عنصر اختیاری است):

  • توضیحات بسته (یک نظر)

  • تمام عبارات load()

  • تابع package() .

  • فراخوانی به قوانین و ماکروها

Buildifier بین یک نظر مستقل و یک نظر متصل به یک عنصر تمایز قائل می شود. اگر نظری به عنصر خاصی متصل نیست، از یک خط خالی بعد از آن استفاده کنید. این تمایز هنگام انجام تغییرات خودکار مهم است (به عنوان مثال، برای حفظ یا حذف نظر هنگام حذف یک قانون).

# Standalone comment (such as to make a section in a file)

# Comment for the cc_library below
cc_library(name = "cc")

ارجاع به اهداف در بسته فعلی

فایل ها باید با مسیرهایشان نسبت به دایرکتوری بسته ارجاع داده شوند (بدون استفاده از مراجع بالا، مانند .. ). فایل های تولید شده باید با پیشوند " : " باشند تا نشان دهند که منبع نیستند. فایل های منبع نباید با پیشوند : . قوانین باید با پیشوند : . به عنوان مثال، فرض کنید x.cc یک فایل منبع است:

cc_library(
    name = "lib",
    srcs = ["x.cc"],
    hdrs = [":gen_header"],
)

genrule(
    name = "gen_header",
    srcs = [],
    outs = ["x.h"],
    cmd = "echo 'int x();' > $@",
)

نام گذاری هدف

نام هدف باید توصیفی باشد. اگر هدف حاوی یک فایل منبع باشد، هدف معمولاً باید نامی برگرفته از آن منبع داشته باشد (به عنوان مثال، یک cc_library برای chat.cc را می‌توان chat نامید، یا یک java_library برای DirectMessage.java را می‌توان direct_message ).

هدف همنام برای یک بسته (هدف با همان نام دایرکتوری حاوی) باید عملکرد توصیف شده توسط نام دایرکتوری را ارائه دهد. اگر چنین هدفی وجود ندارد، هدفی همنام ایجاد نکنید.

هنگام ارجاع به یک هدف همنام، از نام کوتاه استفاده کنید ( //x به جای //x:x ). اگر در همان بسته هستید، مرجع محلی ( :x به جای //x ) را ترجیح دهید.

از استفاده از نام‌های هدف «رزرو شده» که معنای خاصی دارند خودداری کنید. این شامل all ، __pkg__ و __subpackages__ ، این نام‌ها معنای خاصی دارند و هنگام استفاده می‌توانند باعث سردرگمی و رفتارهای غیرمنتظره شوند.

در غیاب یک کنوانسیون غالب تیم، اینها برخی از توصیه های غیر الزام آور هستند که به طور گسترده در Google استفاده می شوند:

  • به طور کلی از "snake_case" استفاده کنید
    • برای java_library با یک src این به معنای استفاده از نامی است که با نام فایل بدون پسوند یکسان نیست.
    • برای قوانین *_binary و *_test ، از "Upper CamelCase" استفاده کنید. این اجازه می دهد تا نام هدف با یکی از src ها مطابقت داشته باشد. برای java_test ، این امکان را فراهم می کند که ویژگی test_class از نام هدف استنتاج شود.
  • اگر چندین نوع از یک هدف خاص وجود دارد، پسوندی برای ابهام‌زدایی اضافه کنید (مانند :foo_dev ، :foo_prod یا :bar_x86 ، :bar_x64 )
  • پسوند اهداف _test با _test ، _unittest ، Test یا Tests
  • از پسوندهای بی معنی مانند _lib یا _library کنید (مگر اینکه برای جلوگیری از درگیری بین یک هدف _library و _binary متناظر آن ضروری باشد)
  • برای اهداف مرتبط با پروتو:
    • اهداف proto_library باید دارای نام هایی باشند که به _proto
    • قوانین *_proto_library مخصوص زبان‌ها باید با پروتوی اصلی مطابقت داشته باشند، اما _proto با پسوند خاص زبان مانند:
      • cc_proto_library : _cc_proto
      • java_proto_library : _java_proto
      • java_lite_proto_library : _java_proto_lite

دید

دید باید تا حد امکان دقیق باشد، در حالی که همچنان امکان دسترسی با آزمایش و وابستگی معکوس وجود دارد. در صورت لزوم از __pkg__ و __subpackages__ استفاده کنید.

از تنظیم بسته default_visibility به //visibility:public اجتناب کنید. //visibility:public باید به صورت جداگانه فقط برای اهداف در API عمومی پروژه تنظیم شود. اینها می‌توانند کتابخانه‌هایی باشند که به گونه‌ای طراحی شده‌اند که توسط پروژه‌های خارجی وابسته باشند یا باینری‌هایی که می‌توانند توسط فرآیند ساخت یک پروژه خارجی مورد استفاده قرار گیرند.

وابستگی ها

وابستگی ها باید به وابستگی های مستقیم (وابستگی های مورد نیاز منابع ذکر شده در قانون) محدود شوند. وابستگی های گذرا را فهرست نکنید.

وابستگی های بسته-محلی باید ابتدا فهرست شوند و به شیوه ای سازگار با مراجع به اهداف در بخش بسته فعلی بالا (نه با نام بسته مطلق آنها) ارجاع داده شوند.

ترجیح دهید وابستگی ها را مستقیماً به عنوان یک لیست واحد فهرست کنید. قرار دادن وابستگی های "مشترک" چندین هدف در یک متغیر، قابلیت نگهداری را کاهش می دهد، ابزارها را نمی توانند وابستگی های یک هدف را تغییر دهند و می تواند منجر به وابستگی های استفاده نشده شود.

گلوب

"بدون هدف" را با [] نشان دهید. از گلوبی استفاده نکنید که با هیچ چیز مطابقت ندارد: این فهرست نسبت به یک لیست خالی بیشتر مستعد خطا و آشکارتر است.

بازگشتی

از glob های بازگشتی برای مطابقت با فایل های منبع استفاده نکنید (به عنوان مثال، glob(["**/*.java"]) ).

glob های بازگشتی استدلال فایل های BUILD را دشوار می کنند زیرا از زیر شاخه های حاوی فایل های BUILD می کنند.

گلوب‌های بازگشتی معمولاً کارایی کمتری نسبت به داشتن یک فایل BUILD در هر دایرکتوری با نمودار وابستگی تعریف‌شده بین آن‌ها دارند، زیرا این امکان ذخیره‌سازی از راه دور و موازی‌سازی بهتر را فراهم می‌کند.

نوشتن یک فایل BUILD در هر دایرکتوری و تعریف یک نمودار وابستگی بین آنها تمرین خوبی است.

غیر بازگشتی

گلوب های غیر بازگشتی به طور کلی قابل قبول هستند.

سایر کنوانسیون ها

  • از حروف بزرگ و زیرخط برای اعلام ثابت ها (مانند GLOBAL_CONSTANT )، از حروف کوچک و زیرخط برای اعلام متغیرها (مانند my_variable ) استفاده کنید.

  • برچسب ها هرگز نباید تقسیم شوند، حتی اگر بیشتر از 79 کاراکتر باشند. تا حد امکان برچسب ها باید به صورت رشته ای باشند. دلیل : یافتن و جایگزینی را آسان می کند. همچنین خوانایی را بهبود می بخشد.

  • مقدار مشخصه name باید یک رشته ثابت تحت اللفظی باشد (به جز در ماکروها). منطق : ابزارهای خارجی از ویژگی name برای ارجاع یک قانون استفاده می کنند. آنها باید قوانینی را بدون نیاز به تفسیر کد پیدا کنند.

  • هنگام تنظیم ویژگی های نوع بولی، از مقادیر بولی استفاده کنید، نه از مقادیر صحیح. به دلایل قدیمی، قوانین همچنان در صورت نیاز اعداد صحیح را به بولی تبدیل می‌کنند، اما این کار منع می‌شود. منطق : flaky = 1 را می‌توان به اشتباه به این صورت خوانده شود که می‌گوید: «این هدف را با یک بار اجرای مجدد آن حذف کنید». flaky = True بدون ابهام می گوید "این تست پوسته پوسته است".

تفاوت با راهنمای سبک پایتون

اگرچه سازگاری با راهنمای سبک پایتون یک هدف است، اما چند تفاوت وجود دارد:

  • بدون محدودیت طول خط. نظرات طولانی و رشته های طولانی اغلب به 79 ستون تقسیم می شوند، اما لازم نیست. نباید در بازبینی کدها یا اسکریپت‌ها از قبل ارسال شود. دلیل : برچسب ها می توانند طولانی باشند و از این حد تجاوز کنند. معمول است که فایل‌های BUILD توسط ابزار تولید یا ویرایش شوند، که با محدودیت طول خط به خوبی پیش نمی‌رود.

  • الحاق رشته ضمنی پشتیبانی نمی شود. از عملگر + استفاده کنید. دلیل : فایل های BUILD حاوی لیست های رشته ای زیادی هستند. به راحتی می توان کاما را فراموش کرد که منجر به یک نتیجه کاملاً متفاوت می شود. این باعث ایجاد باگ های زیادی در گذشته شده است. این بحث را هم ببینید.

  • از فاصله های اطراف علامت = برای آرگومان های کلمات کلیدی در قوانین استفاده کنید. دلیل: آرگومان های نامگذاری شده بسیار بیشتر از پایتون هستند و همیشه در یک خط جداگانه قرار دارند. فضاها خوانایی را بهبود می بخشند. این کنوانسیون مدت زیادی است که وجود داشته است و ارزش تغییر همه فایل های BUILD موجود را ندارد.

  • به‌طور پیش‌فرض، از علامت‌های نقل قول دوتایی برای رشته‌ها استفاده کنید. دلیل : این در راهنمای سبک پایتون مشخص نشده است، اما سازگاری را توصیه می کند. بنابراین ما تصمیم گرفتیم که فقط از رشته های دو نقل قول استفاده کنیم. بسیاری از زبان ها از دو نقل قول برای حرف های رشته ای استفاده می کنند.

  • از یک خط خالی بین دو تعریف سطح بالا استفاده کنید. دلیل : ساختار یک فایل BUILD مانند یک فایل معمولی پایتون نیست. فقط بیانیه های سطح بالا دارد. استفاده از یک خط خالی باعث کوتاه‌تر شدن فایل‌های BUILD می‌شود.