diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..08891d8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true \ No newline at end of file diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..f96b514 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,14 @@ +changelog: + categories: + - title: SemVer Major + labels: + - ⚠️ semver/major + - title: SemVer Minor + labels: + - semver/minor + - title: SemVer Patch + labels: + - semver/patch + - title: Other Changes + labels: + - semver/none diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..400a1b9 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,18 @@ +name: Main + +on: + push: + branches: [main] + schedule: + - cron: "0 8,20 * * *" + +jobs: + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_9_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error" + linux_5_10_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error" + linux_6_0_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..6287586 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,26 @@ +name: PR + +on: + pull_request: + types: [opened, reopened, synchronize] + +jobs: + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + license_header_check_project_name: "Swift Metrics API" + + unit-tests: + name: Unit tests + uses: apple/swift-nio/.github/workflows/unit_tests.yml@main + with: + linux_5_9_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error" + linux_5_10_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error" + linux_6_0_arguments_override: "-Xswiftc -warnings-as-errors --explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_6_0_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + linux_nightly_main_arguments_override: "--explicit-target-dependency-import-check error -Xswiftc -require-explicit-sendable" + + cxx-interop: + name: Cxx interop + uses: apple/swift-nio/.github/workflows/cxx_interop.yml@main diff --git a/.github/workflows/pull_request_label.yml b/.github/workflows/pull_request_label.yml new file mode 100644 index 0000000..86f199f --- /dev/null +++ b/.github/workflows/pull_request_label.yml @@ -0,0 +1,18 @@ +name: PR label + +on: + pull_request: + types: [labeled, unlabeled, opened, reopened, synchronize] + +jobs: + semver-label-check: + name: Semantic Version label check + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Check for Semantic Version label + uses: apple/swift-nio/.github/actions/pull_request_semver_label_checker@main diff --git a/.licenseignore b/.licenseignore new file mode 100644 index 0000000..3fab865 --- /dev/null +++ b/.licenseignore @@ -0,0 +1,35 @@ +.gitignore +**/.gitignore +.licenseignore +.gitattributes +.git-blame-ignore-revs +.mailfilter +.mailmap +.spi.yml +.swift-format +.editorconfig +.github/* +*.md +*.txt +*.yml +*.yaml +*.json +Package.swift +**/Package.swift +Package@-*.swift +**/Package@-*.swift +Package.resolved +**/Package.resolved +Makefile +*.modulemap +**/*.modulemap +**/*.docc/* +*.xcprivacy +**/*.xcprivacy +*.symlink +**/*.symlink +Dockerfile +**/Dockerfile +Snippets/* +dev/git.commit.template +.unacceptablelanguageignore diff --git a/.swift-format b/.swift-format new file mode 100644 index 0000000..7e8ae73 --- /dev/null +++ b/.swift-format @@ -0,0 +1,68 @@ +{ + "version" : 1, + "indentation" : { + "spaces" : 4 + }, + "tabWidth" : 4, + "fileScopedDeclarationPrivacy" : { + "accessLevel" : "private" + }, + "spacesAroundRangeFormationOperators" : false, + "indentConditionalCompilationBlocks" : false, + "indentSwitchCaseLabels" : false, + "lineBreakAroundMultilineExpressionChainComponents" : false, + "lineBreakBeforeControlFlowKeywords" : false, + "lineBreakBeforeEachArgument" : true, + "lineBreakBeforeEachGenericRequirement" : true, + "lineLength" : 120, + "maximumBlankLines" : 1, + "respectsExistingLineBreaks" : true, + "prioritizeKeepingFunctionOutputTogether" : true, + "noAssignmentInExpressions" : { + "allowedFunctions" : [ + "XCTAssertNoThrow", + "XCTAssertThrowsError" + ] + }, + "rules" : { + "AllPublicDeclarationsHaveDocumentation" : false, + "AlwaysUseLiteralForEmptyCollectionInit" : false, + "AlwaysUseLowerCamelCase" : false, + "AmbiguousTrailingClosureOverload" : true, + "BeginDocumentationCommentWithOneLineSummary" : false, + "DoNotUseSemicolons" : true, + "DontRepeatTypeInStaticProperties" : true, + "FileScopedDeclarationPrivacy" : true, + "FullyIndirectEnum" : true, + "GroupNumericLiterals" : true, + "IdentifiersMustBeASCII" : true, + "NeverForceUnwrap" : false, + "NeverUseForceTry" : false, + "NeverUseImplicitlyUnwrappedOptionals" : false, + "NoAccessLevelOnExtensionDeclaration" : true, + "NoAssignmentInExpressions" : true, + "NoBlockComments" : true, + "NoCasesWithOnlyFallthrough" : true, + "NoEmptyTrailingClosureParentheses" : true, + "NoLabelsInCasePatterns" : true, + "NoLeadingUnderscores" : false, + "NoParensAroundConditions" : true, + "NoVoidReturnOnFunctionSignature" : true, + "OmitExplicitReturns" : true, + "OneCasePerLine" : true, + "OneVariableDeclarationPerLine" : true, + "OnlyOneTrailingClosureArgument" : true, + "OrderedImports" : true, + "ReplaceForEachWithForLoop" : true, + "ReturnVoidInsteadOfEmptyTuple" : true, + "UseEarlyExits" : false, + "UseExplicitNilCheckInConditions" : false, + "UseLetInEveryBoundCaseVariable" : false, + "UseShorthandTypeNames" : true, + "UseSingleLinePropertyGetter" : false, + "UseSynthesizedInitializer" : false, + "UseTripleSlashForDocumentationComments" : true, + "UseWhereClausesInForLoops" : false, + "ValidateDocumentationComments" : false + } +} diff --git a/.swiftformat b/.swiftformat deleted file mode 100644 index f2e789d..0000000 --- a/.swiftformat +++ /dev/null @@ -1,16 +0,0 @@ -# file options - ---swiftversion 5.0 ---exclude .build - -# format options - ---self insert ---patternlet inline ---stripunusedargs unnamed-only ---ifdef no-indent - -# Configure the placement of an extension's access control keyword. ---extensionacl on-declarations - -# rules diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11eb1c5..e6a370e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,36 +60,9 @@ We require that your commit messages match our template. The easiest way to do t git config commit.template dev/git.commit.template -### Make sure Tests work on Linux +### Run CI checks locally -SwiftMetrics uses XCTest to run tests on both macOS and Linux. While the macOS version of XCTest is able to use the Objective-C runtime to discover tests at execution time, the Linux version is not. -For this reason, whenever you add new tests **you have to run a script** that generates the hooks needed to run those tests on Linux, or our CI will complain that the tests are not all present on Linux. To do this, merely execute `ruby ./scripts/generate_linux_tests.rb` at the root of the package and check the changes it made. - -### Run `./scripts/soundness.sh` - -The scripts directory contains a [soundness.sh script](https://github.com/apple/swift-metrics/blob/main/scripts/soundness.sh) -that enforces additional checks, like license headers and formatting style. - -Please make sure to `./scripts/soundness.sh` before pushing a change upstream, otherwise it is likely the PR validation will fail -on minor changes such as a missing `self.` or similar formatting issues. - -> The script also executes the above mentioned `generate_linux_tests.rb`. - -For frequent contributors, we recommend adding the script as a [git pre-push hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks), which you can do via executing the following command in the project root directory: - -```bash -cat << EOF > .git/hooks/pre-push -#!/bin/bash - -if [[ -f "scripts/soundness.sh" ]]; then - scripts/soundness.sh -fi -EOF -``` - -Which makes the script execute, and only allow the `git push` to complete if the check has passed. - -In the case of formatting issues, you can then `git add` the formatting changes, and attempt the push again. +You can run the Github Actions workflows locally using [act](https://github.com/nektos/act). For detailed steps on how to do this please see [https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally](https://github.com/swiftlang/github-workflows?tab=readme-ov-file#running-workflows-locally). ## How to contribute your work diff --git a/Package.swift b/Package.swift index d9f7f74..a4ace72 100644 --- a/Package.swift +++ b/Package.swift @@ -22,10 +22,6 @@ let package = Package( .library(name: "Metrics", targets: ["Metrics"]), .library(name: "MetricsTestKit", targets: ["MetricsTestKit"]), ], - dependencies: [ - // ~~~ SwiftPM Plugins ~~~ - .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"), - ], targets: [ .target( name: "CoreMetrics" diff --git a/Sources/CoreMetrics/Metrics.swift b/Sources/CoreMetrics/Metrics.swift index a37cc33..641cb61 100644 --- a/Sources/CoreMetrics/Metrics.swift +++ b/Sources/CoreMetrics/Metrics.swift @@ -48,7 +48,7 @@ public final class Counter { /// Increment the counter. /// /// - parameters: - /// - by: Amount to increment by. + /// - amount: Amount to increment by. @inlinable public func increment(by amount: DataType) { self._handler.increment(by: Int64(amount)) @@ -88,7 +88,7 @@ extension Counter { extension Counter: CustomStringConvertible { public var description: String { - return "Counter(\(self.label), dimensions: \(self.dimensions))" + "Counter(\(self.label), dimensions: \(self.dimensions))" } } @@ -127,7 +127,7 @@ public final class FloatingPointCounter { /// Increment the FloatingPointCounter. /// /// - parameters: - /// - by: Amount to increment by. + /// - amount: Amount to increment by. @inlinable public func increment(by amount: DataType) { self._handler.increment(by: Double(amount)) @@ -167,7 +167,7 @@ extension FloatingPointCounter { extension FloatingPointCounter: CustomStringConvertible { public var description: String { - return "FloatingPointCounter(\(self.label), dimensions: \(self.dimensions))" + "FloatingPointCounter(\(self.label), dimensions: \(self.dimensions))" } } @@ -235,7 +235,7 @@ public final class Meter { /// Increment the Meter. /// /// - parameters: - /// - by: Amount to increment by. + /// - amount: Amount to increment by. @inlinable public func increment(by amount: DataType) { self._handler.increment(by: Double(amount)) @@ -250,7 +250,7 @@ public final class Meter { /// Decrement the Meter. /// /// - parameters: - /// - by: Amount to decrement by. + /// - amount: Amount to decrement by. @inlinable public func decrement(by amount: DataType) { self._handler.decrement(by: Double(amount)) @@ -284,7 +284,7 @@ extension Meter { extension Meter: CustomStringConvertible { public var description: String { - return "\(type(of: self))(\(self.label), dimensions: \(self.dimensions))" + "\(type(of: self))(\(self.label), dimensions: \(self.dimensions))" } } @@ -368,7 +368,7 @@ extension Recorder { extension Recorder: CustomStringConvertible { public var description: String { - return "\(type(of: self))(\(self.label), dimensions: \(self.dimensions), aggregate: \(self.aggregate))" + "\(type(of: self))(\(self.label), dimensions: \(self.dimensions), aggregate: \(self.aggregate))" } } @@ -397,9 +397,18 @@ public struct TimeUnit: Equatable, Sendable { public static let nanoseconds = TimeUnit(code: .nanoseconds, scaleFromNanoseconds: 1) public static let microseconds = TimeUnit(code: .microseconds, scaleFromNanoseconds: 1000) - public static let milliseconds = TimeUnit(code: .milliseconds, scaleFromNanoseconds: 1000 * TimeUnit.microseconds.scaleFromNanoseconds) - public static let seconds = TimeUnit(code: .seconds, scaleFromNanoseconds: 1000 * TimeUnit.milliseconds.scaleFromNanoseconds) - public static let minutes = TimeUnit(code: .minutes, scaleFromNanoseconds: 60 * TimeUnit.seconds.scaleFromNanoseconds) + public static let milliseconds = TimeUnit( + code: .milliseconds, + scaleFromNanoseconds: 1000 * TimeUnit.microseconds.scaleFromNanoseconds + ) + public static let seconds = TimeUnit( + code: .seconds, + scaleFromNanoseconds: 1000 * TimeUnit.milliseconds.scaleFromNanoseconds + ) + public static let minutes = TimeUnit( + code: .minutes, + scaleFromNanoseconds: 60 * TimeUnit.seconds.scaleFromNanoseconds + ) public static let hours = TimeUnit(code: .hours, scaleFromNanoseconds: 60 * TimeUnit.minutes.scaleFromNanoseconds) public static let days = TimeUnit(code: .days, scaleFromNanoseconds: 24 * TimeUnit.hours.scaleFromNanoseconds) } @@ -436,7 +445,7 @@ public final class Timer { /// Record a duration in nanoseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordNanoseconds(_ duration: Int64) { self._handler.recordNanoseconds(duration) @@ -445,7 +454,7 @@ public final class Timer { /// Record a duration in nanoseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordNanoseconds(_ duration: DataType) { self.recordNanoseconds(duration >= Int64.max ? Int64.max : Int64(duration)) @@ -454,7 +463,7 @@ public final class Timer { /// Record a duration in microseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordMicroseconds(_ duration: DataType) { guard duration <= Int64.max else { return self.recordNanoseconds(Int64.max) } @@ -470,7 +479,7 @@ public final class Timer { /// Record a duration in microseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordMicroseconds(_ duration: DataType) { self.recordNanoseconds(Double(duration * 1000) < Double(Int64.max) ? Int64(duration * 1000) : Int64.max) @@ -479,7 +488,7 @@ public final class Timer { /// Record a duration in milliseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordMilliseconds(_ duration: DataType) { guard duration <= Int64.max else { return self.recordNanoseconds(Int64.max) } @@ -495,16 +504,18 @@ public final class Timer { /// Record a duration in milliseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordMilliseconds(_ duration: DataType) { - self.recordNanoseconds(Double(duration * 1_000_000) < Double(Int64.max) ? Int64(duration * 1_000_000) : Int64.max) + self.recordNanoseconds( + Double(duration * 1_000_000) < Double(Int64.max) ? Int64(duration * 1_000_000) : Int64.max + ) } /// Record a duration in seconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordSeconds(_ duration: DataType) { guard duration <= Int64.max else { return self.recordNanoseconds(Int64.max) } @@ -520,10 +531,12 @@ public final class Timer { /// Record a duration in seconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. @inlinable public func recordSeconds(_ duration: DataType) { - self.recordNanoseconds(Double(duration * 1_000_000_000) < Double(Int64.max) ? Int64(duration * 1_000_000_000) : Int64.max) + self.recordNanoseconds( + Double(duration * 1_000_000_000) < Double(Int64.max) ? Int64(duration * 1_000_000_000) : Int64.max + ) } } @@ -544,7 +557,11 @@ extension Timer { /// - label: The label for the `Timer`. /// - dimensions: The dimensions for the `Timer`. /// - displayUnit: A hint to the backend responsible for presenting the data of the preferred display unit. This is not guaranteed to be supported by all backends. - public convenience init(label: String, dimensions: [(String, String)] = [], preferredDisplayUnit displayUnit: TimeUnit) { + public convenience init( + label: String, + dimensions: [(String, String)] = [], + preferredDisplayUnit displayUnit: TimeUnit + ) { let handler = MetricsSystem.factory.makeTimer(label: label, dimensions: dimensions) handler.preferDisplayUnit(displayUnit) self.init(label: label, dimensions: dimensions, handler: handler) @@ -560,7 +577,7 @@ extension Timer { extension Timer: CustomStringConvertible { public var description: String { - return "Timer(\(self.label), dimensions: \(self.dimensions))" + "Timer(\(self.label), dimensions: \(self.dimensions))" } } @@ -589,7 +606,7 @@ public enum MetricsSystem { /// Returns a reference to the configured factory. public static var factory: MetricsFactory { - return self._factory.underlying + self._factory.underlying } /// Acquire a writer lock for the duration of the given block. @@ -597,7 +614,7 @@ public enum MetricsSystem { /// - Parameter body: The block to execute while holding the lock. /// - Returns: The value returned by the block. public static func withWriterLock(_ body: () throws -> T) rethrows -> T { - return try self._factory.withWriterLock(body) + try self._factory.withWriterLock(body) } // This can be `@unchecked Sendable` because we're manually gating access to mutable state with a lock. @@ -612,20 +629,23 @@ public enum MetricsSystem { func replaceFactory(_ factory: MetricsFactory, validate: Bool) { self.lock.withWriterLock { - precondition(!validate || !self.initialized, "metrics system can only be initialized once per process. currently used factory: \(self._underlying)") + precondition( + !validate || !self.initialized, + "metrics system can only be initialized once per process. currently used factory: \(self._underlying)" + ) self._underlying = factory self.initialized = true } } var underlying: MetricsFactory { - return self.lock.withReaderLock { - return self._underlying + self.lock.withReaderLock { + self._underlying } } func withWriterLock(_ body: () throws -> T) rethrows -> T { - return try self.lock.withWriterLock(body) + try self.lock.withWriterLock(body) } } } @@ -891,7 +911,7 @@ extension MetricsFactory { /// - label: The label for the `FloatingPointCounterHandler`. /// - dimensions: The dimensions for the `FloatingPointCounterHandler`. public func makeFloatingPointCounter(label: String, dimensions: [(String, String)]) -> FloatingPointCounterHandler { - return AccumulatingRoundingFloatingPointCounter(label: label, dimensions: dimensions) + AccumulatingRoundingFloatingPointCounter(label: label, dimensions: dimensions) } /// Invoked when the corresponding `FloatingPointCounter`'s `destroy()` function is invoked. @@ -915,7 +935,7 @@ extension MetricsFactory { /// - label: The label for the `MeterHandler`. /// - dimensions: The dimensions for the `MeterHandler`. public func makeMeter(label: String, dimensions: [(String, String)]) -> MeterHandler { - return AccumulatingMeter(label: label, dimensions: dimensions) + AccumulatingMeter(label: label, dimensions: dimensions) } /// Invoked when the corresponding `Meter`'s `destroy()` function is invoked. @@ -1051,7 +1071,7 @@ public protocol TimerHandler: AnyObject, _SwiftMetricsSendableProtocol { /// Record a duration in nanoseconds. /// /// - parameters: - /// - value: Duration to record. + /// - duration: Duration to record. func recordNanoseconds(_ duration: Int64) /// Set the preferred display unit for this TimerHandler. @@ -1077,23 +1097,23 @@ public final class MultiplexMetricsHandler: MetricsFactory { } public func makeCounter(label: String, dimensions: [(String, String)]) -> CounterHandler { - return MuxCounter(factories: self.factories, label: label, dimensions: dimensions) + MuxCounter(factories: self.factories, label: label, dimensions: dimensions) } public func makeFloatingPointCounter(label: String, dimensions: [(String, String)]) -> FloatingPointCounterHandler { - return MuxFloatingPointCounter(factories: self.factories, label: label, dimensions: dimensions) + MuxFloatingPointCounter(factories: self.factories, label: label, dimensions: dimensions) } public func makeMeter(label: String, dimensions: [(String, String)]) -> MeterHandler { - return MuxMeter(factories: self.factories, label: label, dimensions: dimensions) + MuxMeter(factories: self.factories, label: label, dimensions: dimensions) } public func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> RecorderHandler { - return MuxRecorder(factories: self.factories, label: label, dimensions: dimensions, aggregate: aggregate) + MuxRecorder(factories: self.factories, label: label, dimensions: dimensions, aggregate: aggregate) } public func makeTimer(label: String, dimensions: [(String, String)]) -> TimerHandler { - return MuxTimer(factories: self.factories, label: label, dimensions: dimensions) + MuxTimer(factories: self.factories, label: label, dimensions: dimensions) } public func destroyCounter(_ handler: CounterHandler) { @@ -1133,11 +1153,11 @@ public final class MultiplexMetricsHandler: MetricsFactory { } func increment(by amount: Int64) { - self.counters.forEach { $0.increment(by: amount) } + for counter in self.counters { counter.increment(by: amount) } } func reset() { - self.counters.forEach { $0.reset() } + for counter in self.counters { counter.reset() } } } @@ -1148,11 +1168,11 @@ public final class MultiplexMetricsHandler: MetricsFactory { } func increment(by amount: Double) { - self.counters.forEach { $0.increment(by: amount) } + for counter in self.counters { counter.increment(by: amount) } } func reset() { - self.counters.forEach { $0.reset() } + for counter in self.counters { counter.reset() } } } @@ -1163,34 +1183,36 @@ public final class MultiplexMetricsHandler: MetricsFactory { } func set(_ value: Int64) { - self.meters.forEach { $0.set(value) } + for meter in self.meters { meter.set(value) } } func set(_ value: Double) { - self.meters.forEach { $0.set(value) } + for meter in self.meters { meter.set(value) } } func increment(by amount: Double) { - self.meters.forEach { $0.increment(by: amount) } + for meter in self.meters { meter.increment(by: amount) } } func decrement(by amount: Double) { - self.meters.forEach { $0.decrement(by: amount) } + for meter in self.meters { meter.decrement(by: amount) } } } private final class MuxRecorder: RecorderHandler { let recorders: [RecorderHandler] public init(factories: [MetricsFactory], label: String, dimensions: [(String, String)], aggregate: Bool) { - self.recorders = factories.map { $0.makeRecorder(label: label, dimensions: dimensions, aggregate: aggregate) } + self.recorders = factories.map { + $0.makeRecorder(label: label, dimensions: dimensions, aggregate: aggregate) + } } func record(_ value: Int64) { - self.recorders.forEach { $0.record(value) } + for recorder in self.recorders { recorder.record(value) } } func record(_ value: Double) { - self.recorders.forEach { $0.record(value) } + for recorder in self.recorders { recorder.record(value) } } } @@ -1201,39 +1223,41 @@ public final class MultiplexMetricsHandler: MetricsFactory { } func recordNanoseconds(_ duration: Int64) { - self.timers.forEach { $0.recordNanoseconds(duration) } + for timer in self.timers { timer.recordNanoseconds(duration) } } func preferDisplayUnit(_ unit: TimeUnit) { - self.timers.forEach { $0.preferDisplayUnit(unit) } + for timer in self.timers { timer.preferDisplayUnit(unit) } } } } /// Ships with the metrics module, used for initial bootstrapping. -public final class NOOPMetricsHandler: MetricsFactory, CounterHandler, FloatingPointCounterHandler, MeterHandler, RecorderHandler, TimerHandler { +public final class NOOPMetricsHandler: MetricsFactory, CounterHandler, FloatingPointCounterHandler, MeterHandler, + RecorderHandler, TimerHandler +{ public static let instance = NOOPMetricsHandler() private init() {} public func makeCounter(label: String, dimensions: [(String, String)]) -> CounterHandler { - return self + self } public func makeFloatingPointCounter(label: String, dimensions: [(String, String)]) -> FloatingPointCounterHandler { - return self + self } public func makeMeter(label: String, dimensions: [(String, String)]) -> MeterHandler { - return self + self } public func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> RecorderHandler { - return self + self } public func makeTimer(label: String, dimensions: [(String, String)]) -> TimerHandler { - return self + self } public func destroyCounter(_: CounterHandler) {} diff --git a/Sources/Metrics/Metrics.swift b/Sources/Metrics/Metrics.swift index 58e8ff3..7a3ea82 100644 --- a/Sources/Metrics/Metrics.swift +++ b/Sources/Metrics/Metrics.swift @@ -13,9 +13,10 @@ //===----------------------------------------------------------------------===// @_exported import CoreMetrics -@_exported import class CoreMetrics.Timer import Foundation +@_exported import class CoreMetrics.Timer + extension Timer { /// Convenience for measuring duration of a closure. /// @@ -24,7 +25,11 @@ extension Timer { /// - dimensions: The dimensions for the Timer. /// - body: Closure to run & record. @inlinable - public static func measure(label: String, dimensions: [(String, String)] = [], body: @escaping () throws -> T) rethrows -> T { + public static func measure( + label: String, + dimensions: [(String, String)] = [], + body: @escaping () throws -> T + ) rethrows -> T { let timer = Timer(label: label, dimensions: dimensions) let start = DispatchTime.now().uptimeNanoseconds defer { @@ -88,7 +93,7 @@ extension Timer { } extension Timer { - /// Convenience for recording a duration based on ``Duration``. + /// Convenience for recording a duration based on `Duration`. /// /// `Duration` will be converted to an `Int64` number of nanoseconds, and then recorded with nanosecond precision. /// diff --git a/Sources/MetricsTestKit/TestMetrics.swift b/Sources/MetricsTestKit/TestMetrics.swift index aabc635..1acb675 100644 --- a/Sources/MetricsTestKit/TestMetrics.swift +++ b/Sources/MetricsTestKit/TestMetrics.swift @@ -69,7 +69,7 @@ public final class TestMetrics: MetricsFactory { } public func makeCounter(label: String, dimensions: [(String, String)]) -> CounterHandler { - return self.lock.withLock { () -> CounterHandler in + self.lock.withLock { () -> CounterHandler in if let existing = self._counters[.init(label: label, dimensions: dimensions)] { return existing } @@ -80,7 +80,7 @@ public final class TestMetrics: MetricsFactory { } public func makeMeter(label: String, dimensions: [(String, String)]) -> MeterHandler { - return self.lock.withLock { () -> MeterHandler in + self.lock.withLock { () -> MeterHandler in if let existing = self._meters[.init(label: label, dimensions: dimensions)] { return existing } @@ -91,7 +91,7 @@ public final class TestMetrics: MetricsFactory { } public func makeRecorder(label: String, dimensions: [(String, String)], aggregate: Bool) -> RecorderHandler { - return self.lock.withLock { () -> RecorderHandler in + self.lock.withLock { () -> RecorderHandler in if let existing = self._recorders[.init(label: label, dimensions: dimensions)] { return existing } @@ -102,7 +102,7 @@ public final class TestMetrics: MetricsFactory { } public func makeTimer(label: String, dimensions: [(String, String)]) -> TimerHandler { - return self.lock.withLock { () -> TimerHandler in + self.lock.withLock { () -> TimerHandler in if let existing = self._timers[.init(label: label, dimensions: dimensions)] { return existing } @@ -148,15 +148,15 @@ public final class TestMetrics: MetricsFactory { extension TestMetrics.FullKey: Hashable { public func hash(into hasher: inout Hasher) { self.label.hash(into: &hasher) - self.dimensions.forEach { dim in + for dim in self.dimensions { dim.0.hash(into: &hasher) dim.1.hash(into: &hasher) } } public static func == (lhs: TestMetrics.FullKey, rhs: TestMetrics.FullKey) -> Bool { - return lhs.label == rhs.label && - Dictionary(uniqueKeysWithValues: lhs.dimensions) == Dictionary(uniqueKeysWithValues: rhs.dimensions) + lhs.label == rhs.label + && Dictionary(uniqueKeysWithValues: lhs.dimensions) == Dictionary(uniqueKeysWithValues: rhs.dimensions) } } @@ -193,11 +193,11 @@ extension TestMetrics { // MARK: - Gauge public func expectGauge(_ metric: Gauge) throws -> TestRecorder { - return try self.expectRecorder(metric) + try self.expectRecorder(metric) } public func expectGauge(_ label: String, _ dimensions: [(String, String)] = []) throws -> TestRecorder { - return try self.expectRecorder(label, dimensions) + try self.expectRecorder(label, dimensions) } // MARK: - Meter @@ -299,7 +299,7 @@ public final class TestCounter: TestMetric, CounterHandler, Equatable { public let dimensions: [(String, String)] public var key: TestMetrics.FullKey { - return TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) + TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) } let lock = NSLock() @@ -318,33 +318,33 @@ public final class TestCounter: TestMetric, CounterHandler, Equatable { } public func reset() { - return self.lock.withLock { + self.lock.withLock { self._values = [] } } public var lastValue: Int64? { - return self.last?.1 + self.last?.1 } public var totalValue: Int64 { - return self.values.reduce(0, +) + self.values.reduce(0, +) } public var last: (Date, Int64)? { - return self.lock.withLock { + self.lock.withLock { self._values.last } } public var values: [Int64] { - return self.lock.withLock { + self.lock.withLock { self._values.map { $0.1 } } } public static func == (lhs: TestCounter, rhs: TestCounter) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } } @@ -354,7 +354,7 @@ public final class TestMeter: TestMetric, MeterHandler, Equatable { public let dimensions: [(String, String)] public var key: TestMetrics.FullKey { - return TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) + TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) } let lock = NSLock() @@ -430,23 +430,23 @@ public final class TestMeter: TestMetric, MeterHandler, Equatable { } public var lastValue: Double? { - return self.last?.1 + self.last?.1 } public var last: (Date, Double)? { - return self.lock.withLock { + self.lock.withLock { self._values.last } } public var values: [Double] { - return self.lock.withLock { + self.lock.withLock { self._values.map { $0.1 } } } public static func == (lhs: TestMeter, rhs: TestMeter) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } } @@ -457,7 +457,7 @@ public final class TestRecorder: TestMetric, RecorderHandler, Equatable { public let aggregate: Bool public var key: TestMetrics.FullKey { - return TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) + TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) } let lock = NSLock() @@ -482,23 +482,23 @@ public final class TestRecorder: TestMetric, RecorderHandler, Equatable { } public var lastValue: Double? { - return self.last?.1 + self.last?.1 } public var last: (Date, Double)? { - return self.lock.withLock { + self.lock.withLock { self._values.last } } public var values: [Double] { - return self.lock.withLock { + self.lock.withLock { self._values.map { $0.1 } } } public static func == (lhs: TestRecorder, rhs: TestRecorder) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } } @@ -509,7 +509,7 @@ public final class TestTimer: TestMetric, TimerHandler, Equatable { public let dimensions: [(String, String)] public var key: TestMetrics.FullKey { - return TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) + TestMetrics.FullKey(label: self.label, dimensions: self.dimensions) } let lock = NSLock() @@ -543,23 +543,23 @@ public final class TestTimer: TestMetric, TimerHandler, Equatable { } public var lastValue: Int64? { - return self.last?.1 + self.last?.1 } public var values: [Int64] { - return self.lock.withLock { - return self._values.map { $0.1 } + self.lock.withLock { + self._values.map { $0.1 } } } public var last: (Date, Int64)? { - return self.lock.withLock { - return self._values.last + self.lock.withLock { + self._values.last } } public static func == (lhs: TestTimer, rhs: TestTimer) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } } diff --git a/Tests/MetricsTests/CoreMetricsTests.swift b/Tests/MetricsTests/CoreMetricsTests.swift index bf62fe4..8454289 100644 --- a/Tests/MetricsTests/CoreMetricsTests.swift +++ b/Tests/MetricsTests/CoreMetricsTests.swift @@ -12,10 +12,11 @@ // //===----------------------------------------------------------------------===// -@testable import CoreMetrics import MetricsTestKit import XCTest +@testable import CoreMetrics + class MetricsTests: XCTestCase { func testCounters() throws { // bootstrap with our test metrics @@ -25,12 +26,12 @@ class MetricsTests: XCTestCase { let name = "counter-\(UUID().uuidString)" let counter = Counter(label: name) let testCounter = try metrics.expectCounter(counter) - let total = Int.random(in: 500 ... 1000) - for _ in 0 ..< total { + let total = Int.random(in: 500...1000) + for _ in 0.. [Int64] in @@ -40,7 +41,7 @@ class SendableTest: XCTestCase { do { let name = "floating-point-counter-\(UUID().uuidString)" - let value = Double.random(in: 0 ... 0.9999) + let value = Double.random(in: 0...0.9999) let counter = FloatingPointCounter(label: name) let task = Task.detached { () -> Double in @@ -54,7 +55,7 @@ class SendableTest: XCTestCase { do { let name = "recorder-\(UUID().uuidString)" - let value = Double.random(in: -1000 ... 1000) + let value = Double.random(in: -1000...1000) let recorder = Recorder(label: name) let task = Task.detached { () -> [Double] in @@ -69,7 +70,7 @@ class SendableTest: XCTestCase { do { let name = "meter-\(UUID().uuidString)" - let value = Double.random(in: -1000 ... 1000) + let value = Double.random(in: -1000...1000) let meter = Meter(label: name) let task = Task.detached { () -> [Double] in @@ -84,7 +85,7 @@ class SendableTest: XCTestCase { do { let name = "timer-\(UUID().uuidString)" - let value = Int64.random(in: 0 ... 1000) + let value = Int64.random(in: 0...1000) let timer = Timer(label: name) let task = Task.detached { () -> [Int64] in diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 5fc04d7..0000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,31 +0,0 @@ -ARG swift_version=5.7 -ARG ubuntu_version=focal -ARG base_image=swift:$swift_version-$ubuntu_version -FROM $base_image -# needed to do again after FROM due to docker limitation -ARG swift_version -ARG ubuntu_version - -# set as UTF-8 -RUN apt-get update && apt-get install -y locales locales-all -ENV LC_ALL en_US.UTF-8 -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US.UTF-8 - -# dependencies -RUN apt-get update && apt-get install -y wget -RUN apt-get update && apt-get install -y lsof dnsutils netcat-openbsd net-tools curl jq # used by integration tests - -# ruby and jazzy for docs generation -RUN apt-get update && apt-get install -y ruby ruby-dev libsqlite3-dev build-essential - -# tools -RUN mkdir -p $HOME/.tools -RUN echo 'export PATH="$HOME/.tools:$PATH"' >> $HOME/.profile - -# swiftformat (until part of the toolchain) - -ARG swiftformat_version=0.49.6 -RUN if [ "${swift_version}" = "5.7" ]; then git clone --branch $swiftformat_version --depth 1 https://github.com/nicklockwood/SwiftFormat $HOME/.tools/swift-format; fi -RUN if [ "${swift_version}" = "5.7" ]; then cd $HOME/.tools/swift-format && swift build -c release; fi -RUN if [ "${swift_version}" = "5.7" ]; then ln -s $HOME/.tools/swift-format/.build/release/swiftformat $HOME/.tools/swiftformat; fi diff --git a/docker/docker-compose.2004.58.yaml b/docker/docker-compose.2004.58.yaml deleted file mode 100644 index 07bfd51..0000000 --- a/docker/docker-compose.2004.58.yaml +++ /dev/null @@ -1,18 +0,0 @@ -version: "3" - -services: - - runtime-setup: - image: swift-metrics:20.04-5.8 - build: - args: - ubuntu_version: "focal" - swift_version: "5.8" - - test: - image: swift-metrics:20.04-5.8 - environment: [] - #- SANITIZER_ARG=--sanitize=thread - - shell: - image: swift-metrics:20.04-5.8 diff --git a/docker/docker-compose.2204.510.yaml b/docker/docker-compose.2204.510.yaml deleted file mode 100644 index 21955d2..0000000 --- a/docker/docker-compose.2204.510.yaml +++ /dev/null @@ -1,17 +0,0 @@ -version: "3" - -services: - - runtime-setup: - image: swift-metrics:22.04-5.10 - build: - args: - base_image: "swiftlang/swift:nightly-5.10-jammy" - - test: - image: swift-metrics:22.04-5.10 - environment: [] - #- SANITIZER_ARG=--sanitize=thread - - shell: - image: swift-metrics:22.04-5.10 diff --git a/docker/docker-compose.2204.59.yaml b/docker/docker-compose.2204.59.yaml deleted file mode 100644 index 7912dae..0000000 --- a/docker/docker-compose.2204.59.yaml +++ /dev/null @@ -1,18 +0,0 @@ -version: "3" - -services: - - runtime-setup: - image: swift-metrics:22.04-5.9 - build: - args: - ubuntu_version: "jammy" - swift_version: "5.9" - - test: - image: swift-metrics:22.04-5.9 - environment: [] - #- SANITIZER_ARG=--sanitize=thread - - shell: - image: swift-metrics:22.04-5.9 diff --git a/docker/docker-compose.2204.main.yaml b/docker/docker-compose.2204.main.yaml deleted file mode 100644 index b45215a..0000000 --- a/docker/docker-compose.2204.main.yaml +++ /dev/null @@ -1,17 +0,0 @@ -version: "3" - -services: - - runtime-setup: - image: swift-metrics:22.04-main - build: - args: - base_image: "swiftlang/swift:nightly-main-jammy" - - test: - image: swift-metrics:22.04-main - environment: [] - #- SANITIZER_ARG=--sanitize=thread - - shell: - image: swift-metrics:22.04-main diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml deleted file mode 100644 index 8d26d65..0000000 --- a/docker/docker-compose.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# this file is not designed to be run directly -# instead, use the docker-compose.. files -# eg docker-compose -f docker/docker-compose.yaml -f docker/docker-compose.1804.50.yaml run test -version: "3" - -services: - - runtime-setup: - image: swift-metrics:default - build: - context: . - dockerfile: Dockerfile - - common: &common - image: swift-metrics:default - depends_on: [runtime-setup] - volumes: - - ~/.ssh:/root/.ssh - - ..:/code:z - working_dir: /code - cap_drop: - - CAP_NET_RAW - - CAP_NET_BIND_SERVICE - - soundness: - <<: *common - command: /bin/bash -xcl "./scripts/soundness.sh" - - test: - <<: *common - command: /bin/bash -xcl "swift test -Xswiftc -warnings-as-errors $${SANITIZER_ARG-}" - - # util - - shell: - <<: *common - entrypoint: /bin/bash -l diff --git a/scripts/build_podspec.sh b/scripts/build_podspec.sh deleted file mode 100755 index 6ccb6e2..0000000 --- a/scripts/build_podspec.sh +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift Metrics API open source project -## -## Copyright (c) 2019 Apple Inc. and the Swift Metrics API project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of Swift Metrics API project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2017-2018 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu - -function usage() { - echo "$0 [-u] version" - echo - echo "OPTIONS:" - echo " -u: Additionally upload the podspec" -} - -upload=false -while getopts ":u" opt; do - case $opt in - u) - upload=true - ;; - \?) - usage - exit 1 - ;; - esac -done -shift "$((OPTIND-1))" - -if [[ $# -eq 0 ]]; then - echo "Must provide target version" - exit 1 -fi - -version=$1 -name="SwiftMetrics" - -here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -tmpdir=$(mktemp -d /tmp/.build_podspecsXXXXXX) -echo "Building podspec in $tmpdir" - - cat >> "${tmpdir}/${name}.podspec" <<- EOF -Pod::Spec.new do |s| - s.name = '$name' - s.version = '$version' - s.license = { :type => 'Apache 2.0', :file => 'LICENSE.txt' } - s.summary = 'A Metrics API for Swift.' - s.homepage = 'https://github.com/apple/swift-metrics' - s.author = 'Apple Inc.' - s.source = { :git => 'https://github.com/apple/swift-metrics.git', :tag => s.version.to_s } - s.documentation_url = 'https://apple.github.io/swift-metrics' - s.module_name = '$name' - - s.swift_version = '4.2' - s.cocoapods_version = '>=1.6.0' - s.ios.deployment_target = '8.0' - s.osx.deployment_target = '10.9' - s.tvos.deployment_target = '9.0' - s.watchos.deployment_target = '2.0' - - s.source_files = 'Sources/CoreMetrics/**/*.swift' -end -EOF - -if $upload; then - echo "Uploading ${tmpdir}/${name}.podspec" - pod trunk push "${tmpdir}/${name}.podspec" -else - echo "Linting ${tmpdir}/${name}.podspec" - pod spec lint "${tmpdir}/${name}.podspec" -fi diff --git a/scripts/check_no_api_breakages.sh b/scripts/check_no_api_breakages.sh deleted file mode 100755 index 986fdda..0000000 --- a/scripts/check_no_api_breakages.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift Metrics API open source project -## -## Copyright (c) 2019 Apple Inc. and the Swift Metrics API project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of Swift Metrics API project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2017-2020 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu - -function usage() { - echo >&2 "Usage: $0 REPO-GITHUB-URL NEW-VERSION OLD-VERSIONS..." - echo >&2 - echo >&2 "This script requires a Swift 5.2+ toolchain." - echo >&2 - echo >&2 "Examples:" - echo >&2 - echo >&2 "Check between main and tag 2.1.1 of swift-nio:" - echo >&2 " $0 https://github.com/apple/swift-nio main 2.1.1" - echo >&2 - echo >&2 "Check between HEAD and commit 64cf63d7 using the provided toolchain:" - echo >&2 " xcrun --toolchain org.swift.5120190702a $0 ../some-local-repo HEAD 64cf63d7" -} - -if [[ $# -lt 3 ]]; then - usage - exit 1 -fi - -tmpdir=$(mktemp -d /tmp/.check-api_XXXXXX) -repo_url=$1 -new_tag=$2 -shift 2 - -repodir="$tmpdir/repo" -git clone "$repo_url" "$repodir" -git -C "$repodir" fetch -q origin '+refs/pull/*:refs/remotes/origin/pr/*' -cd "$repodir" -git checkout -q "$new_tag" - -for old_tag in "$@"; do - echo "Checking public API breakages from $old_tag to $new_tag" - - swift package diagnose-api-breaking-changes "$old_tag" -done - -echo done diff --git a/scripts/preview_docc.sh b/scripts/preview_docc.sh deleted file mode 100755 index 4eb0dc3..0000000 --- a/scripts/preview_docc.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift Metrics API open source project -## -## Copyright (c) 2018-2019 Apple Inc. and the Swift Metrics API project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of Swift Metrics API project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -swift package --disable-sandbox preview-documentation --target "$1" diff --git a/scripts/soundness.sh b/scripts/soundness.sh deleted file mode 100755 index 21ee5e5..0000000 --- a/scripts/soundness.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift Metrics API open source project -## -## Copyright (c) 2018-2019 Apple Inc. and the Swift Metrics API project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of Swift Metrics API project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftNIO open source project -## -## Copyright (c) 2017-2019 Apple Inc. and the SwiftNIO project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftNIO project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu -here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -function replace_acceptable_years() { - # this needs to replace all acceptable forms with 'YEARS' - sed -e 's/20[12][789012]-20[12][89012]/YEARS/' -e 's/20[12][89012]/YEARS/' -} - -printf "=> Checking for unacceptable language... " -# This greps for unacceptable terminology. The square bracket[s] are so that -# "git grep" doesn't find the lines that greps :). -unacceptable_terms=( - -e blacklis[t] - -e whitelis[t] - -e slav[e] - -e sanit[y] -) -if git grep --color=never -i "${unacceptable_terms[@]}" > /dev/null; then - printf "\033[0;31mUnacceptable language found.\033[0m\n" - git grep -i "${unacceptable_terms[@]}" - exit 1 -fi -printf "\033[0;32mokay.\033[0m\n" - -printf "=> Checking format... " - -if [[ ! -x $(which swiftformat) ]]; then - printf "\033[0;31mswiftformat not found!\033[0m\n" - exit 1 -fi - -FIRST_OUT="$(git status --porcelain)" -swiftformat . > /dev/null 2>&1 -SECOND_OUT="$(git status --porcelain)" -if [[ "$FIRST_OUT" != "$SECOND_OUT" ]]; then - printf "\033[0;31mformatting issues!\033[0m\n" - git --no-pager diff - exit 1 -else - printf "\033[0;32mokay.\033[0m\n" -fi - -printf "=> Checking license headers\n" -tmp=$(mktemp /tmp/.swift-metrics-soundness_XXXXXX) - -for language in swift-or-c bash dtrace; do - printf " * $language... " - declare -a matching_files - declare -a exceptions - expections=( ) - matching_files=( -name '*' ) - case "$language" in - swift-or-c) - exceptions=( -name Package.swift -o -name "Package@swift-*.swift" ) - matching_files=( -name '*.swift' -o -name '*.c' -o -name '*.h' ) - cat > "$tmp" <<"EOF" -//===----------------------------------------------------------------------===// -// -// This source file is part of the Swift Metrics API open source project -// -// Copyright (c) YEARS Apple Inc. and the Swift Metrics API project authors -// Licensed under Apache License v2.0 -// -// See LICENSE.txt for license information -// See CONTRIBUTORS.txt for the list of Swift Metrics API project authors -// -// SPDX-License-Identifier: Apache-2.0 -// -//===----------------------------------------------------------------------===// -EOF - ;; - bash) - matching_files=( -name '*.sh' ) - cat > "$tmp" <<"EOF" -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the Swift Metrics API open source project -## -## Copyright (c) YEARS Apple Inc. and the Swift Metrics API project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of Swift Metrics API project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## -EOF - ;; - dtrace) - matching_files=( -name '*.d' ) - cat > "$tmp" <<"EOF" -#!/usr/sbin/dtrace -q -s -/*===----------------------------------------------------------------------===* - * - * This source file is part of the Swift Metrics API open source project - * - * Copyright (c) YEARS Apple Inc. and the Swift Metrics API project authors - * Licensed under Apache License v2.0 - * - * See LICENSE.txt for license information - * See CONTRIBUTORS.txt for the list of Swift Metrics API project authors - * - * SPDX-License-Identifier: Apache-2.0 - * - *===----------------------------------------------------------------------===*/ -EOF - ;; - *) - echo >&2 "ERROR: unknown language '$language'" - ;; - esac - - expected_lines=$(cat "$tmp" | wc -l) - expected_sha=$(cat "$tmp" | shasum) - - ( - cd "$here/.." - find . \ - \( \! -path './.build/*' -a \ - \( "${matching_files[@]}" \) -a \ - \( \! \( "${exceptions[@]}" \) \) \) | while read line; do - if [[ "$(cat "$line" | replace_acceptable_years | head -n $expected_lines | shasum)" != "$expected_sha" ]]; then - printf "\033[0;31mmissing headers in file '$line'!\033[0m\n" - diff -u <(cat "$line" | replace_acceptable_years | head -n $expected_lines) "$tmp" - exit 1 - fi - done - printf "\033[0;32mokay.\033[0m\n" - ) -done - -rm "$tmp"