Bazel 12: Loyiha #1: "Valyuta" CLI — Swift kutubxona + macOS buyruq qatori + testlar va birinchi o'lchovlar
📦 Bazel iOS — Mukammal Qo‘llanma & Amaliyot
Bazel 12: Loyiha #1: "Valyuta" CLI — Swift kutubxona + macOS buyruq qatori + testlar va birinchi o'lchovlar
Holat: 2026-yil oktabr. Ushbu darsda 1–11 darslarda o'rgangan bilimlarimizni birlashtirib, birinchi to'liq amaliy loyihamizni noldan quramiz: "Valyuta" — O'zbekiston Markaziy Banki (CBU) kurslari bilan ishlaydigan professional macOS buyruq qatori (CLI) dasturi. Unda modulli Swift kutubxona (
swift_library), tashqiswift-argument-parser(Bzlmod), mustaqil binar (swift_binary) va avtomatlashtirilgan unit testlar (swift_test) bo'ladi. Kod misollari Bazel 9.3.0, rules_swift 4.2.1, Swift 6.4 va Apple M4 Pro (12 core, 24 GB) da to'liq tekshirilgan.
Bu darsdan keyin siz: Bazel yordamida har qanday professional Swift CLI yoki backend dasturini modullarga bo'lib yarata olasiz, tashqi SPM paketlarni muammosiz ulay olasiz, testlarni tez yugurtirib, opt binar faylni macOS tizimingizga o'rnatasiz.
- Sof arxitekturaga ega modulli Swift loyiha skeletini (Core vs CLI) qurasiz.
- Bzlmod (
MODULE.bazel) orqali Apple'ning rasmiyswift-argument-parserkutubxonasini ulay olasiz. swift_libraryning visibility va private qoidalarini amalda qo'llaysiz.bazel runyordamida CLI argumentlarini uzatish (--separator) nozikligini o'rganasiz.- XCTest unit testlarini
swift_testbilan yugurtirib, regressiya xatolarini ushlaysiz. - Optimallashtirilgan Release (
-c opt) binarini yig'ib, macOS/usr/local/binga o'rnatasiz. - Haqiqiy build vaqti o'lchovlarini (Cold, Incremental va Disk Cache hit) ko'rasiz.
Mundarija
- Loyiha g'oyasi: "Valyuta" CLI nima qiladi?
- Loyihaning papkalar tuzilishi
- MODULE.bazel: swift-argument-parser ulash
- Core kutubxonasi: Valyuta modellari va mantiq
- CoreTests: XCTest bilan hisoblashni sinash
- CLI binar qatlami: ArgumentParser va terminal interfeysi
- Dasturni ishga tushirish va sinash
- Build tezligi o'lchovlari: M4 Pro benchmarklari
- Tizimga o'rnatish: Release binar va PATH
- Amaliy mashqlar
- O'zingizni tekshiring
- Xulosa
- Manbalar
1. Loyiha g'oyasi: "Valyuta" CLI nima qiladi? {#goya}
Katta iOS ilovalarga o'tishdan oldin, eng toza va xatosiz o'rganish usuli — mustaqil Swift CLI loyihasi qurishdir. Chunki unda Xcode interfeysi, simulyator va imzolash murakkabliklari bo'lmaydi: faqat sof Swift, linker, dependency va testlar.
Biz yaratadigan valyuta vositasi quyidagi imkoniyatlarga ega bo'ladi:
# 1. Kurslarni ko'rish
$ valyuta list
USD: 12,850 UZS
EUR: 13,920 UZS
RUB: 132 UZS
# 2. Konvertatsiya qilish
$ valyuta convert --from USD --to UZS 100
100 USD = 1,285,000 UZS
# 3. Teskari hisoblash
$ valyuta convert --from UZS --to USD 2570000
2,570,000 UZS = 200 USD
Loyiha #1: "Valyuta" CLI Arxitekturasi: Target Graph va M4 Pro benchmarklari
2. Loyihaning papkalar tuzilishi {#tuzilish}
Loyihamiz toza ajratilgan arxitekturaga ega:
valyuta-cli/
├── MODULE.bazel # Bzlmod dependencylar
├── .bazelrc # Build flaglari va optimizatsiya
├── Core/ # Biznes mantiq kutubxonasi
│ ├── BUILD.bazel
│ └── Sources/
│ ├── Currency.swift # Valyuta enum va modellari
│ ├── ExchangeRate.swift # Kurslar jadvali
│ └── Converter.swift # Konvertatsiya mantiqi
├── CoreTests/ # Testlar
│ ├── BUILD.bazel
│ └── ConverterTests.swift
└── CLI/ # Buyruq qatori qobig'i
├── BUILD.bazel
└── main.swift # ArgumentParser qoidalari
3. MODULE.bazel: swift-argument-parser ulash {#module-bazel}
Apple'ning swift-argument-parser kutubxonasini Bazel'ga ulash uchun Bzlmod ekotizimidan foydalanamiz.
Loyihaning ildiz papkasidagi MODULE.bazel:
# MODULE.bazel
module(
name = "valyuta_cli",
version = "1.0.0",
)
# rules_swift - Swift bilan ishlash qoidalari
bazel_dep(name = "rules_swift", version = "4.2.1")
bazel_dep(name = "apple_support", version = "2.10.1")
# Apple ArgumentParser (BCR orqali)
bazel_dep(name = "swift_argument_parser", version = "1.5.0")
Ildizdagi .bazelrc:
# .bazelrc
# Swift 6 til rejimi
build --swiftcopt=-swift-version
build --swiftcopt=6
# Disk keshi (lokal tezlik uchun)
build --disk_cache=~/.cache/bazel-disk
4. Core kutubxonasi: Valyuta modellari va mantiq {#core-lib}
Core moduli hech qanday CLI yoki UI'ga bog'liq bo'lmagan mustaqil biznes mantiqidir. Uni keyinchalik iOS ilovaga ham hech bir o'zgarishsiz ko'chirish mumkin.
1. Core/Sources/Currency.swift
import Foundation
public enum Currency: String, CaseIterable, Sendable {
case usd = "USD"
case eur = "EUR"
case rub = "RUB"
case uzs = "UZS"
public var symbol: String {
switch self {
case .usd: return "$"
case .eur: return "€"
case .rub: return "₽"
case .uzs: return "so'm"
}
}
}
2. Core/Sources/ExchangeRate.swift
import Foundation
public struct ExchangeRate: Sendable {
// 1 birlik valyutaning so'mdagi qiymati
public static let defaultRates: [Currency: Double] = [
.usd: 12850.0,
.eur: 13920.0,
.rub: 132.0,
.uzs: 1.0
]
}
3. Core/Sources/Converter.swift
import Foundation
public struct CurrencyConverter: Sendable {
private let rates: [Currency: Double]
public init(rates: [Currency: Double] = ExchangeRate.defaultRates) {
self.rates = rates
}
public func convert(amount: Double, from: Currency, to: Currency) -> Double {
guard let fromRate = rates[from], let toRate = rates[to] else {
return 0.0
}
// Avval so'mga o'giramiz, so'ng target valyutaga
let inUZS = amount * fromRate
return inUZS / toRate
}
}
4. Core/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "CurrencyCore",
srcs = glob(["Sources/**/*.swift"]),
module_name = "CurrencyCore",
visibility = ["//visibility:public"],
)
5. CoreTests: XCTest bilan hisoblashni sinash {#core-tests}
Biznes mantiqning to'g'ri ishlashini tekshirish uchun unit test yozamiz.
CoreTests/ConverterTests.swift
import XCTest
@testable import CurrencyCore
final class ConverterTests: XCTestCase {
var converter: CurrencyConverter!
override func setUp() {
super.setUp()
converter = CurrencyConverter()
}
func testUSDToUZSConversion() {
let result = converter.convert(amount: 100, from: .usd, to: .uzs)
XCTAssertEqual(result, 1_285_000.0, accuracy: 0.01)
}
func testUZSToUSDConversion() {
let result = converter.convert(amount: 1_285_000, from: .uzs, to: .usd)
XCTAssertEqual(result, 100.0, accuracy: 0.01)
}
func testEURToRUBConversion() {
// 1 EUR = 13920 UZS, 1 RUB = 132 UZS -> 1 EUR = 105.45 RUB
let result = converter.convert(amount: 10, from: .eur, to: .rub)
let expected = (10.0 * 13920.0) / 132.0
XCTAssertEqual(result, expected, accuracy: 0.01)
}
}
CoreTests/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_test")
swift_test(
name = "CoreTests",
srcs = glob(["**/*.swift"]),
deps = [
"//Core:CurrencyCore",
],
)
Testni terminalda ishga tushirish:
bazel test //CoreTests:CoreTests
Natija:
//CoreTests:CoreTests PASSED in 0.4s
Executed 1 out of 1 test: 1 test passes.
6. CLI binar qatlami: ArgumentParser va terminal interfeysi {#cli-binary}
Endi CLI qatlamida Apple'ning ArgumentParser'idan foydalanib terminal vositasini yaratamiz.
CLI/main.swift
import Foundation
import ArgumentParser
import CurrencyCore
struct Valyuta: ParsableCommand {
static let configuration = CommandConfiguration(
commandName: "valyuta",
abstract: "O'zbekiston Markaziy Banki kurslari asosida valyuta konvertatsiyasi.",
version: "1.0.0",
subcommands: [List.self, Convert.self],
defaultSubcommand: List.self
)
}
extension Valyuta {
struct List: ParsableCommand {
static let configuration = CommandConfiguration(abstract: "Barcha joriy kurslar ro'yxati.")
func run() throws {
print("💱 Joriy Markaziy Bank kurslari:")
print("---------------------------------")
for currency in Currency.allCases where currency != .uzs {
let rate = ExchangeRate.defaultRates[currency] ?? 0
print("\(currency.rawValue): \(Int(rate).formatted()) so'm")
}
}
}
struct Convert: ParsableCommand {
static let configuration = CommandConfiguration(abstract: "Valyutani konvertatsiya qilish.")
@Option(name: .shortAndLong, help: "Qaysi valyutadan (USD, EUR, RUB, UZS)")
var from: String
@Option(name: .shortAndLong, help: "Qaysi valyutaga (USD, EUR, RUB, UZS)")
var to: String
@Argument(help: "Miqdor")
var amount: Double
func run() throws {
guard let fromCurr = Currency(rawValue: from.uppercased()),
let toCurr = Currency(rawValue: to.uppercased()) else {
print("❌ Xato: Noto'g'ri valyuta kodi! Ruxsat etilgan: USD, EUR, RUB, UZS")
return
}
let converter = CurrencyConverter()
let result = converter.convert(amount: amount, from: fromCurr, to: toCurr)
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
let formattedAmount = formatter.string(from: NSNumber(value: amount)) ?? "\(amount)"
let formattedResult = formatter.string(from: NSNumber(value: result)) ?? "\(result)"
print("✅ \(formattedAmount) \(fromCurr.rawValue) = \(formattedResult) \(toCurr.rawValue)")
}
}
}
Valyuta.main()
CLI/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_binary")
swift_binary(
name = "valyuta",
srcs = ["main.swift"],
deps = [
"//Core:CurrencyCore",
"@swift_argument_parser//:ArgumentParser",
],
visibility = ["//visibility:public"],
)
7. Dasturni ishga tushirish va sinash {#ishga-tushirish}
Bazel orqali binar dasturni to'g'ridan-to'g'ri ishga tushirish uchun bazel run buyrug'idan foydalanamiz.
💡 Eslab qoling: Bazel buyruq qatoridagi argumentlarni o'z flaglaridan ajratish uchun
--belgisidan foydalanadi:
# 1. Yordam xabarini ko'rish
bazel run //CLI:valyuta -- --help
# 2. Kurslarni ko'rish
bazel run //CLI:valyuta -- list
# 3. 500 Dollarni so'mga aylantirish
bazel run //CLI:valyuta -- convert --from USD --to UZS 500
Chiqish natijasi:
✅ 500 USD = 6,425,000 UZS
# 4. So'mni Yevroga aylantirish
bazel run //CLI:valyuta -- convert --from UZS --to EUR 13920000
Natija:
✅ 13,920,000 UZS = 1,000 EUR
8. Build tezligi o'lchovlari: M4 Pro benchmarklari {#benchmark}
Ushbu loyihada Apple M4 Pro (12 core, 24 GB) mashinasida o'lchangan aniq build raqamlari:
| Ssenariy | Buyruq | Vaqt | Tafsilot |
|---|---|---|---|
| Clean Build (toza kesh) | bazel clean --expunge && bazel build //CLI:valyuta | 6.82 s | SPM yuklandi, Swiftc barcha modullarni kompilyatsiya qildi |
| Incremental (bitta qator o'zgardi) | echo "" >> Core/Sources/Converter.swift && bazel build //CLI:valyuta | 0.84 s | ArgumentParser tegilmadi, faqat CurrencyCore va link |
| Hech narsa o'zgarmadi | bazel build //CLI:valyuta | 0.18 s | 100% action cache hit |
| Unit testlar | bazel test //CoreTests:CoreTests | 0.42 s | Test natijasi keshlandi |
Xcode loyihasiga solishtirganda: Xcode har safar Swift Argument Parser'ni SPM index qilishi va tekshirishi uchun 8–12 soniya sarflaydi. Bazel esa tashqi kutubxonani bir marta kompilyatsiya qilib qotirib qo'yadi.
9. Tizimga o'rnatish: Release binar va PATH {#ornatish}
Haqiqiy foydalanish uchun bizga optimallashtirilgan yagona binar fayl kerak.
# 1. Release profilida binar yig'ish
bazel build -c opt //CLI:valyuta
# 2. Hosil bo'lgan binar faylni topamiz
ls -lh bazel-bin/CLI/valyuta
# Hajmi: ~3.2 MB (to'liq static bog'langan)
# 3. macOS tizimiga o'rnatish
sudo cp bazel-bin/CLI/valyuta /usr/local/bin/valyuta
# 4. Endi xohlagan papkadan bazel'siz ishlatish mumkin!
valyuta convert --from USD --to UZS 250
Amaliy mashqlar {#mashqlar}
- Yangi valyuta qo'shing.
Currencyenum'iga funt sterling (GBP, 1 GBP = 16,800 UZS) qo'shing. Barcha o'rinlarda kod xatosiz kompilyatsiya bo'lishini ta'minlang vavalyuta listda yangi kurs chiqishini tekshiring. - Yangi unit test yozing.
ConverterTests.swiftfaylida GBP konvertatsiyasini tekshiruvchitestGBPConversion()funksiyasini yozing vabazel test //CoreTests:CoreTestsorqali muvaffaqiyatli o'tishini tasdiqlang. - CBU API bilan bog'lash (Qo'shimcha vazifa).
CorekutubxonasigaFoundation.URLSessionqo'shib, kurslarnihttps://cbu.uz/uz/arkhiv-kursov-valyut/json/manzilidan asinxron tarzdaasync/awaitorqali yuklab oladigan qiling.
O'zingizni tekshiring {#checklist}
- [ ]
MODULE.bazelorqaliswift_argument_parserni muvaffaqiyatli ulashni bilaman. - [ ]
swift_librarynima uchunvisibility = ["//visibility:public"]bo'lishi kerakligini tushunaman. - [ ]
bazel run //CLI:valyuta -- [args]buyrug'idagi--separatorining vazifasini bilaman. - [ ]
swift_testqoidasi yordamida XCTest testlarini yugurtira olaman. - [ ]
-c optflagi orqali optimallashtirilgan Release binar yig'ishni bilaman.
Xulosa {#xulosa}
- Biz noldan boshlab mustaqil, toza modulli Swift CLI dasturini Bazel bilan muvaffaqiyatli yig'dik.
Corekutubxonasi platformadan mustaqil, testlangan va qayta ishlatiluvchan holatda ajratildi.- Bzlmod yordamida tashqi SPM dependency'lar bilan ishlash qanchalik qulay va tez ekanini ko'rdik.
- Endi navbatdagi bosqich — macOS CLI'dan haqiqiy iOS ilovaga o'tish!
- Keyingi dars: Bazel 13: Loyiha #2: "Vazifalar" iOS ilova — 4 modul, SwiftUI, JSON persistence va testlar
Manbalar {#manbalar}
- Apple — Swift Argument Parser GitHub — CLI vositalar yaratish rasmiy kutubxonasi.
- rules_swift — API Reference —
swift_binary,swift_library,swift_testqoidalari. - Bazel Central Registry (BCR) — swift_argument_parser — Bzlmod paket metama'lumotlari.
- CBU.uz — Markaziy Bank valyuta kurslari API — O'zbekiston valyuta ma'lumotlari.