# Swift Package Plugins Rehberi: Build Sürecinizi Otomatikleştirin
Swift Package Manager artık sadece dependency yönetimi aracı değil — tam teşekküllü bir build otomasyon platformu. Swift 5.6 ile tanıtılan Package Plugins, build sürecinize custom adımlar eklemenize, kod üretmenize ve projenizdeki tekrarlayan görevleri otomatikleştirmenize olanak tanıyor. Eğer hala manuel linting, kod üretimi veya dokümantasyon scriptleri çalıştırıyorsanız, bu rehber hayatınızı değiştirecek.
Not: Bu rehberdeki tüm örnekler Swift 5.9+ ve Xcode 15+ ile test edilmiştir.
İçindekiler
- Package Plugins Nedir?
- Plugin Türleri
- Build Tool Plugin Oluşturma
- Command Plugin Oluşturma
- Gerçek Dünya Örnekleri
- Plugin Güvenlik Modeli
- CI/CD Entegrasyonu
- Karşılaştırma Tablosu
- ALTIN İPUCU
- Sonuç ve Öneriler
1. Package Plugins Nedir?
Swift Package Plugins, SPM build sürecine müdahale etmenizi sağlayan Swift ile yazılmış araçlardır. İki ana türü vardır:
- Build Tool Plugins: Derleme sırasında otomatik çalışır (kod üretimi, asset işleme)
- Command Plugins: Manuel olarak tetiklenir (linting, formatting, dokümantasyon)
Her iki tür de sandbox içinde çalışır ve sisteminize sınırlı erişime sahiptir.
Neden Plugin Kullanmalısınız?
- Tekrarı ortadan kaldırır: Her build öncesi çalıştırdığınız scriptler artık otomatik
- Platform bağımsız: macOS, Linux — her yerde aynı şekilde çalışır
- Type-safe: Plugin'ler Swift ile yazılır, derleme zamanı güvenliği sağlar
- Paylaşılabilir: Plugin'leri package olarak dağıtabilirsiniz
swift
1// Package.swift - Plugin tanımı2// swift-tools-version: 5.93import PackageDescription4 5let package = Package(6 name: "MyApp",7 products: [8 .library(name: "MyApp", targets: ["MyApp"])9 ],10 targets: [11 // Ana target12 .target(13 name: "MyApp",14 plugins: [15 .plugin(name: "CodeGenPlugin")16 ]17 ),18 // Plugin target19 .plugin(20 name: "CodeGenPlugin",21 capability: .buildTool()22 )23 ]24)2. Plugin Türleri Detaylı Karşılaştırma
Özellik | Build Tool Plugin | Command Plugin |
|---|---|---|
**Çalışma Zamanı** | Her build'de otomatik | Manuel tetikleme |
**Sandbox** | Tam sandbox | Kısıtlı (izin ile genişler) |
**Dosya Yazma** | Sadece build dizinine | Proje dizinine (izinle) |
**Kullanım Alanı** | Kod üretimi, asset işleme | Linting, formatting, deploy |
**Performans Etkisi** | Build süresini uzatabilir | Build süresini etkilemez |
**Xcode Desteği** | Tam entegrasyon | Sağ tık menüsünden |
**CI/CD** | Otomatik çalışır | swift package komutu ile |
3. Build Tool Plugin Oluşturma
Build Tool Plugin'ler her derleme öncesinde çalışır ve genellikle kaynak kod üretmek için kullanılır.
Temel Yapı
swift
1// Plugins/CodeGenPlugin/CodeGenPlugin.swift2import PackagePlugin3import Foundation4 5@main6struct CodeGenPlugin: BuildToolPlugin {7 func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {8 // Source target olduğundan emin ol9 guard let sourceTarget = target as? SourceModuleTarget else {10 return []11 }12 13 // Giriş dosyalarını bul (.codegen.json uzantılı)14 let inputFiles = sourceTarget.sourceFiles.filter { file in15 file.path.extension == "json" && file.path.stem.hasSuffix(".codegen")16 }17 18 // Her dosya için bir build komutu oluştur19 return inputFiles.map { inputFile in20 let outputName = inputFile.path.stem21 .replacingOccurrences(of: ".codegen", with: "")22 let outputPath = context.pluginWorkDirectory23 .appending("Generated_\(outputName).swift")24 25 return .buildCommand(26 displayName: "CodeGen: \(outputName)",27 executable: try! context.tool(named: "codegen-tool").path,28 arguments: [29 "--input", inputFile.path.string,30 "--output", outputPath.string31 ],32 inputFiles: [inputFile.path],33 outputFiles: [outputPath]34 )35 }36 }37}Pre-Build vs Build Command
Build Tool Plugin'ler iki tür komut döndürebilir:
- buildCommand: Giriş dosyaları değiştiğinde çalışır (incremental)
- prebuildCommand: Her build öncesi çalışır (her seferinde)
swift
1// Prebuild Command örneği - her build'de çalışır2func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {3 let outputDir = context.pluginWorkDirectory.appending("Generated")4 5 return [6 .prebuildCommand(7 displayName: "Generate Build Info",8 executable: try context.tool(named: "build-info-generator").path,9 arguments: ["--output-dir", outputDir.string],10 outputFilesDirectory: outputDir11 )12 ]13}Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
4. Command Plugin Oluşturma
Command Plugin'ler manuel tetiklenir ve proje üzerinde daha geniş yetkiye sahiptir.
swift
1// Plugins/LintPlugin/LintPlugin.swift2import PackagePlugin3 4@main5struct LintPlugin: CommandPlugin {6 func performCommand(7 context: PluginContext,8 arguments: [String]9 ) async throws {10 // SwiftLint aracını bul11 let swiftLint = try context.tool(named: "swiftlint")12 13 // Target'ları belirle14 var argExtractor = ArgumentExtractor(arguments)15 let targetNames = argExtractor.extractOption(named: "target")16 17 let targets: [Target]18 if targetNames.isEmpty {19 targets = context.package.targets20 } else {21 targets = try context.package.targets(named: targetNames)22 }23 24 // Her target için lint çalıştır25 for target in targets {26 guard let sourceTarget = target as? SourceModuleTarget else {27 continue28 }29 30 let process = Process()31 process.executableURL = URL(fileURLWithPath: swiftLint.path.string)32 process.arguments = [33 "lint",34 "--path", sourceTarget.directory.string,35 "--reporter", "emoji"36 ]37 38 try process.run()39 process.waitUntilExit()40 41 if process.terminationStatus != 0 {42 Diagnostics.warning("SwiftLint \(target.name) icin uyarilar buldu")43 }44 }45 }46}5. Gerçek Dünya Örnekleri
Örnek 1: Mock Generator Plugin
Test dosyalarınız için otomatik mock üretimi:
swift
1// Plugins/MockGenPlugin/MockGenPlugin.swift2import PackagePlugin3 4@main5struct MockGenPlugin: BuildToolPlugin {6 func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {7 guard let target = target as? SourceModuleTarget else { return [] }8 9 // Protocol dosyalarını bul10 let protocolFiles = target.sourceFiles.filter { file in11 file.path.extension == "swift"12 }13 14 let outputDir = context.pluginWorkDirectory.appending("Mocks")15 16 return [17 .prebuildCommand(18 displayName: "Generate Mocks for \(target.name)",19 executable: try context.tool(named: "mockgen").path,20 arguments: [21 "--sources", target.directory.string,22 "--output", outputDir.string,23 "--testable-import", target.name24 ],25 outputFilesDirectory: outputDir26 )27 ]28 }29}Örnek 2: Asset Catalog Validator
Build sırasında asset'lerinizi doğrulayın:
swift
1struct AssetValidatorPlugin: BuildToolPlugin {2 func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {3 guard let target = target as? SourceModuleTarget else { return [] }4 5 // .xcassets dizinlerini bul6 let assetCatalogs = target.sourceFiles.filter { file in7 file.path.extension == "xcassets"8 }9 10 guard !assetCatalogs.isEmpty else { return [] }11 12 let reportPath = context.pluginWorkDirectory.appending("asset-report.txt")13 14 return [15 .prebuildCommand(16 displayName: "Validate Assets",17 executable: try context.tool(named: "asset-validator").path,18 arguments: assetCatalogs.map { item in item.path.string } +19 ["--output", reportPath.string],20 outputFilesDirectory: context.pluginWorkDirectory21 )22 ]23 }24}6. Plugin Güvenlik Modeli
SPM plugin'leri sandbox içinde çalışır. Bu güvenlik katmanını anlamak kritik öneme sahiptir.
Sandbox Kuralları
İzin | Build Tool | Command (varsayılan) | Command (genişletilmiş) |
|---|---|---|---|
Kaynak okuma | Sadece target dizini | Sadece target dizini | Tüm proje |
Dosya yazma | Plugin work dir | Yok | Proje dizini |
Ağ erişimi | Yok | Yok | Yok |
Process çalıştırma | Tanımlı araçlar | Tanımlı araçlar | Tanımlı araçlar |
Ortam değişkenleri | Sınırlı | Sınırlı | Sınırlı |
7. CI/CD Entegrasyonu
Plugin'lerinizi CI/CD pipeline'ına entegre etmek kolaydır:
bash
1# GitHub Actions - Command plugin kullanımı2swift package plugin --allow-writing-to-package-directory lint-code3swift package plugin --allow-writing-to-package-directory format-code --target MyApp4 5# Build tool plugin'ler otomatik çalışır6swift build7swift testswift
1// Cache-aware build tool plugin2func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {3 let cacheFile = context.pluginWorkDirectory.appending("input-hashes.json")4 var cachedHashes = loadHashes(from: cacheFile)5 6 let sourceTarget = target as! SourceModuleTarget7 let changedFiles = sourceTarget.sourceFiles.filter { file in8 let currentHash = computeSHA256(file.path)9 let isCached = cachedHashes[file.path.string] == currentHash10 cachedHashes[file.path.string] = currentHash11 if isCached { Diagnostics.remark("Cache hit: \(file.path.lastComponent)") }12 return !isCached13 }14 15 saveHashes(cachedHashes, to: cacheFile)16 // Sadece degisen dosyalar icin build command olustur17 return changedFiles.map { createCommand(for: $0, context: context) }18}ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Okuyucu Ödülü
Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:
Sonuç ve Öneriler
Swift Package Plugins, build sürecinizi modernleştirmenin en etkili yoludur. Manuel scriptlerden kurtulun, tekrarlayan görevleri otomatikleştirin ve ekibinizin verimliliğini artırın. Build Tool Plugin'lerle kod üretimi yapın, Command Plugin'lerle linting ve formatting'i standartlaştırın. Plugin'lerinizi ayrı package olarak yayınlayarak toplulukla paylaşmayı da unutmayın.

