From 6aa85beca6ad2ba9462881c6d2d177b8272f38f0 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Fri, 21 Apr 2023 13:10:09 +0100 Subject: [PATCH] TSCBasic: deprecate `<<<` operator Since TSCBasic has become a kitchen sink for multiple types and functions, it's important to be able to selectively import those. It is done by `import struct` and similar statements. Unfortunately, this doesn't work for operators, which means you have to import the whole module when you need access just to a single operator. This inadvertently pollutes the environment of available symbols, which is undesirable. By deprecating the operator and adding a `send(_:)` function on `WritableByteStream` we allow selectively importing this functionality. --- Sources/TSCBasic/DiagnosticsEngine.swift | 6 +- Sources/TSCBasic/FileSystem.swift | 2 +- Sources/TSCBasic/JSON.swift | 34 ++--- Sources/TSCBasic/Process.swift | 16 +-- Sources/TSCBasic/TerminalController.swift | 10 +- Sources/TSCBasic/WritableByteStream.swift | 85 +++++++++---- Sources/TSCUtility/ArgumentParser.swift | 33 +++-- .../ArgumentParserShellCompletion.swift | 116 +++++++++--------- Sources/TSCUtility/Diagnostics.swift | 4 +- Sources/TSCUtility/ProgressAnimation.swift | 20 +-- .../SHA256PerfTests.swift | 2 +- .../WritableByteStreamPerfTests.swift | 22 ++-- Tests/TSCBasicTests/ByteStringTests.swift | 2 +- Tests/TSCBasicTests/FileSystemTests.swift | 4 +- Tests/TSCBasicTests/ProcessTests.swift | 2 +- Tests/TSCBasicTests/SHA256Tests.swift | 2 +- Tests/TSCBasicTests/TemporaryFileTests.swift | 12 +- .../WritableByteStreamTests.swift | 45 ++++--- .../PkgConfigParserTests.swift | 4 +- .../SimplePersistenceTests.swift | 4 +- 20 files changed, 230 insertions(+), 195 deletions(-) diff --git a/Sources/TSCBasic/DiagnosticsEngine.swift b/Sources/TSCBasic/DiagnosticsEngine.swift index 2f3df235..8bdc4580 100644 --- a/Sources/TSCBasic/DiagnosticsEngine.swift +++ b/Sources/TSCBasic/DiagnosticsEngine.swift @@ -148,11 +148,11 @@ public final class DiagnosticsEngine: CustomStringConvertible { public var description: String { let stream = BufferedOutputByteStream() - stream <<< "[" + stream.send("[") for diag in diagnostics { - stream <<< diag.description <<< ", " + stream.send(diag.description).send(", ") } - stream <<< "]" + stream.send("]") return stream.bytes.description } } diff --git a/Sources/TSCBasic/FileSystem.swift b/Sources/TSCBasic/FileSystem.swift index 77b66baf..739c2547 100644 --- a/Sources/TSCBasic/FileSystem.swift +++ b/Sources/TSCBasic/FileSystem.swift @@ -458,7 +458,7 @@ private struct LocalFileSystem: FileSystem { } break } - data <<< tmpBuffer[0.. 3 { args = args.suffix(from: 3).map({$0}) } - stream <<< args.map({ $0.spm_shellEscaped() }).joined(separator: " ") + stream.send(args.map({ $0.spm_shellEscaped() }).joined(separator: " ")) // Include the output, if present. if let output = try? result.utf8Output() + result.utf8stderrOutput() { // We indent the output to keep it visually separated from everything else. let indentation = " " - stream <<< " output:\n" <<< indentation <<< output.replacingOccurrences(of: "\n", with: "\n" + indentation) + stream.send(" output:\n").send(indentation).send(output.replacingOccurrences(of: "\n", with: "\n" + indentation)) if !output.hasSuffix("\n") { - stream <<< "\n" + stream.send("\n") } } @@ -1333,7 +1333,7 @@ extension FileHandle: WritableByteStream { extension Process { @available(*, deprecated) fileprivate static func logToStdout(_ message: String) { - stdoutStream <<< message <<< "\n" + stdoutStream.send(message).send("\n") stdoutStream.flush() } } diff --git a/Sources/TSCBasic/TerminalController.swift b/Sources/TSCBasic/TerminalController.swift index 001e62a2..19556e58 100644 --- a/Sources/TSCBasic/TerminalController.swift +++ b/Sources/TSCBasic/TerminalController.swift @@ -166,13 +166,13 @@ public final class TerminalController { /// Clears the current line and moves the cursor to beginning of the line.. public func clearLine() { - stream <<< clearLineString <<< "\r" + stream.send(clearLineString).send("\r") flush() } /// Moves the cursor y columns up. public func moveCursor(up: Int) { - stream <<< "\u{001B}[\(up)A" + stream.send("\u{001B}[\(up)A") flush() } @@ -184,7 +184,7 @@ public final class TerminalController { /// Inserts a new line character into the stream. public func endLine() { - stream <<< "\n" + stream.send("\n") flush() } @@ -198,9 +198,9 @@ public final class TerminalController { private func writeWrapped(_ string: String, inColor color: Color, bold: Bool = false, stream: WritableByteStream) { // Don't wrap if string is empty or color is no color. guard !string.isEmpty && color != .noColor else { - stream <<< string + stream.send(string) return } - stream <<< color.string <<< (bold ? boldString : "") <<< string <<< resetString + stream.send(color.string).send(bold ? boldString : "").send(string).send(resetString) } } diff --git a/Sources/TSCBasic/WritableByteStream.swift b/Sources/TSCBasic/WritableByteStream.swift index 0a5d63c2..a59c4dbd 100644 --- a/Sources/TSCBasic/WritableByteStream.swift +++ b/Sources/TSCBasic/WritableByteStream.swift @@ -27,11 +27,11 @@ public protocol ByteStreamable { /// different output destinations, e.g., a file or an in memory buffer. This is /// loosely modeled on LLVM's llvm::raw_ostream class. /// -/// The stream is generally used in conjunction with the custom streaming -/// operator '<<<'. For example: +/// The stream is generally used in conjunction with the `appending` function. +/// For example: /// /// let stream = BufferedOutputByteStream() -/// stream <<< "Hello, world!" +/// stream.appending("Hello, world!") /// /// would write the UTF8 encoding of "Hello, world!" to the stream. /// @@ -39,7 +39,7 @@ public protocol ByteStreamable { /// in the `Format` struct (used for namespacing purposes). For example: /// /// let items = ["hello", "world"] -/// stream <<< Format.asSeparatedList(items, separator: " ") +/// stream.appending(Format.asSeparatedList(items, separator: " ")) /// /// would write each item in the list to the stream, separating them with a /// space. @@ -137,6 +137,34 @@ extension WritableByteStream { } } } + + // MARK: helpers that return `self` + + // FIXME: This override shouldn't be necesary but removing it causes a 30% performance regression. This problem is + // tracked by the following bug: https://bugs.swift.org/browse/SR-8535 + @discardableResult + public func send(_ value: ArraySlice) -> WritableByteStream { + value.write(to: self) + return self + } + + @discardableResult + public func send(_ value: ByteStreamable) -> WritableByteStream { + value.write(to: self) + return self + } + + @discardableResult + public func send(_ value: CustomStringConvertible) -> WritableByteStream { + value.description.write(to: self) + return self + } + + @discardableResult + public func send(_ value: ByteStreamable & CustomStringConvertible) -> WritableByteStream { + value.write(to: self) + return self + } } /// The `WritableByteStream` base class. @@ -366,24 +394,29 @@ precedencegroup StreamingPrecedence { // FIXME: This override shouldn't be necesary but removing it causes a 30% performance regression. This problem is // tracked by the following bug: https://bugs.swift.org/browse/SR-8535 + +@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead") @discardableResult public func <<< (stream: WritableByteStream, value: ArraySlice) -> WritableByteStream { value.write(to: stream) return stream } +@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead") @discardableResult public func <<< (stream: WritableByteStream, value: ByteStreamable) -> WritableByteStream { value.write(to: stream) return stream } +@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead") @discardableResult public func <<< (stream: WritableByteStream, value: CustomStringConvertible) -> WritableByteStream { value.description.write(to: stream) return stream } +@available(*, deprecated, message: "use send(_:) function on WritableByteStream instead") @discardableResult public func <<< (stream: WritableByteStream, value: ByteStreamable & CustomStringConvertible) -> WritableByteStream { value.write(to: stream) @@ -450,7 +483,7 @@ public struct Format { let value: Bool func write(to stream: WritableByteStream) { - stream <<< (value ? "true" : "false") + stream.send(value ? "true" : "false") } } @@ -463,7 +496,7 @@ public struct Format { func write(to stream: WritableByteStream) { // FIXME: Diagnose integers which cannot be represented in JSON. - stream <<< value.description + stream.send(value.description) } } @@ -478,7 +511,7 @@ public struct Format { // FIXME: What should we do about NaN, etc.? // // FIXME: Is Double.debugDescription the best representation? - stream <<< value.debugDescription + stream.send(value.debugDescription) } } @@ -494,9 +527,9 @@ public struct Format { let value: String func write(to stream: WritableByteStream) { - stream <<< UInt8(ascii: "\"") + stream.send(UInt8(ascii: "\"")) stream.writeJSONEscaped(value) - stream <<< UInt8(ascii: "\"") + stream.send(UInt8(ascii: "\"")) } } @@ -514,12 +547,12 @@ public struct Format { let items: [String] func write(to stream: WritableByteStream) { - stream <<< UInt8(ascii: "[") + stream.send(UInt8(ascii: "[")) for (i, item) in items.enumerated() { - if i != 0 { stream <<< "," } - stream <<< Format.asJSON(item) + if i != 0 { stream.send(",") } + stream.send(Format.asJSON(item)) } - stream <<< UInt8(ascii: "]") + stream.send(UInt8(ascii: "]")) } } @@ -531,12 +564,12 @@ public struct Format { let items: [String: String] func write(to stream: WritableByteStream) { - stream <<< UInt8(ascii: "{") + stream.send(UInt8(ascii: "{")) for (offset: i, element: (key: key, value: value)) in items.enumerated() { - if i != 0 { stream <<< "," } - stream <<< Format.asJSON(key) <<< ":" <<< Format.asJSON(value) + if i != 0 { stream.send(",") } + stream.send(Format.asJSON(key)).send(":").send(Format.asJSON(value)) } - stream <<< UInt8(ascii: "}") + stream.send(UInt8(ascii: "}")) } } @@ -551,12 +584,12 @@ public struct Format { let transform: (T) -> String func write(to stream: WritableByteStream) { - stream <<< UInt8(ascii: "[") + stream.send(UInt8(ascii: "[")) for (i, item) in items.enumerated() { - if i != 0 { stream <<< "," } - stream <<< Format.asJSON(transform(item)) + if i != 0 { stream.send(",") } + stream.send(Format.asJSON(transform(item))) } - stream <<< UInt8(ascii: "]") + stream.send(UInt8(ascii: "]")) } } @@ -572,10 +605,10 @@ public struct Format { for (i, item) in items.enumerated() { // Add the separator, if necessary. if i != 0 { - stream <<< separator + stream.send(separator) } - stream <<< item + stream.send(item) } } } @@ -596,8 +629,8 @@ public struct Format { func write(to stream: WritableByteStream) { for (i, item) in items.enumerated() { - if i != 0 { stream <<< separator } - stream <<< transform(item) + if i != 0 { stream.send(separator) } + stream.send(transform(item)) } } } @@ -617,7 +650,7 @@ public struct Format { func write(to stream: WritableByteStream) { for _ in 0..= maxWidth - padding { - stream <<< argument <<< "\n" + stream.send(argument).send("\n") // Align full width because usage is to be printed on a new line. - stream <<< Format.asRepeating(string: " ", count: maxWidth + padding) + stream.send(Format.asRepeating(string: " ", count: maxWidth + padding)) } else { - stream <<< argument + stream.send(argument) // Align to the remaining empty space on the line. - stream <<< Format.asRepeating(string: " ", count: maxWidth - count) + stream.send(Format.asRepeating(string: " ", count: maxWidth - count)) } - stream <<< usage + stream.send(usage) } - stream <<< "OVERVIEW: " <<< overview + stream.send("OVERVIEW: ").send(overview) if !usage.isEmpty { - stream <<< "\n\n" + stream.send("\n\n") // Get the binary name from command line arguments. let defaultCommandName = CommandLine.arguments[0].components(separatedBy: "/").last! - stream <<< "USAGE: " <<< (commandName ?? defaultCommandName) <<< " " <<< usage + stream.send("USAGE: ").send(commandName ?? defaultCommandName).send(" ").send(usage) } if optionArguments.count > 0 { - stream <<< "\n\n" - stream <<< "OPTIONS:" + stream.send("\n\nOPTIONS:") for argument in optionArguments.lazy.sorted(by: { $0.name < $1.name }) { guard let usage = argument.usage else { continue } // Create name with its shortname, if available. @@ -997,8 +996,7 @@ public final class ArgumentParser { } if subparsers.keys.count > 0 { - stream <<< "\n\n" - stream <<< "SUBCOMMANDS:" + stream.send("\n\nSUBCOMMANDS:") for (command, parser) in subparsers.sorted(by: { $0.key < $1.key }) { // Special case for hidden subcommands. guard !parser.overview.isEmpty else { continue } @@ -1007,8 +1005,7 @@ public final class ArgumentParser { } if positionalArguments.count > 0 { - stream <<< "\n\n" - stream <<< "POSITIONAL ARGUMENTS:" + stream.send("\n\nPOSITIONAL ARGUMENTS:") for argument in positionalArguments { guard let usage = argument.usage else { continue } print(formatted: argument.name, usage: usage, on: stream) @@ -1016,11 +1013,11 @@ public final class ArgumentParser { } if let seeAlso = seeAlso { - stream <<< "\n\n" - stream <<< "SEE ALSO: \(seeAlso)" + stream.send("\n\n") + stream.send("SEE ALSO: \(seeAlso)") } - stream <<< "\n" + stream.send("\n") stream.flush() } } diff --git a/Sources/TSCUtility/ArgumentParserShellCompletion.swift b/Sources/TSCUtility/ArgumentParserShellCompletion.swift index be772987..1b714b65 100644 --- a/Sources/TSCUtility/ArgumentParserShellCompletion.swift +++ b/Sources/TSCUtility/ArgumentParserShellCompletion.swift @@ -29,18 +29,18 @@ extension ArgumentParser { switch shell { case .bash: // Information about how to include this function in a completion script. - stream <<< """ + stream.send(""" # Generates completions for \(commandName) # # Parameters # - the start position of this parser; set to 1 if unknown - """ + """) generateBashSwiftTool(name: name, on: stream) case .zsh: // Information about how to include this function in a completion script. - stream <<< """ + stream.send(""" # Generates completions for \(commandName) # # In the final compdef file, set the following file header: @@ -49,7 +49,7 @@ extension ArgumentParser { # local context state state_descr line # typeset -A opt_args - """ + """) generateZshSwiftTool(name: name, on: stream) } @@ -59,11 +59,11 @@ extension ArgumentParser { // MARK: - BASH fileprivate func generateBashSwiftTool(name: String, on stream: WritableByteStream) { - stream <<< """ + stream.send(""" function \(name) { - """ + """) // Suggest positional arguments. Beware that this forces positional arguments // before options. For example [swift package pin ] expects a name as the @@ -71,13 +71,13 @@ extension ArgumentParser { // the positional argument; [swift package pin MyPackage ] will list them // just fine. for (index, argument) in positionalArguments.enumerated() { - stream <<< " if [[ $COMP_CWORD == $(($1+\(index))) ]]; then\n" + stream.send(" if [[ $COMP_CWORD == $(($1+\(index))) ]]; then\n") generateBashCompletion(argument, on: stream) - stream <<< " fi\n" + stream.send(" fi\n") } // Suggest subparsers in addition to other arguments. - stream <<< " if [[ $COMP_CWORD == $1 ]]; then\n" + stream.send(" if [[ $COMP_CWORD == $1 ]]; then\n") var completions = [String]() for (subName, _) in subparsers { completions.append(subName) @@ -88,37 +88,37 @@ extension ArgumentParser { completions.append(shortName) } } - stream <<< """ + stream.send(""" COMPREPLY=( $(compgen -W "\(completions.joined(separator: " "))" -- $cur) ) return fi - """ + """) // Suggest completions based on previous word. generateBashCasePrev(on: stream) // Forward completions to subparsers. - stream <<< " case ${COMP_WORDS[$1]} in\n" + stream.send(" case ${COMP_WORDS[$1]} in\n") for (subName, _) in subparsers { - stream <<< """ + stream.send(""" (\(subName)) \(name)_\(subName) $(($1+1)) return ;; - """ + """) } - stream <<< " esac\n" + stream.send(" esac\n") // In all other cases (no positional / previous / subparser), suggest // this parsers completions. - stream <<< """ + stream.send(""" COMPREPLY=( $(compgen -W "\(completions.joined(separator: " "))" -- $cur) ) } - """ + """) for (subName, subParser) in subparsers { subParser.generateBashSwiftTool(name: "\(name)_\(subName)", on: stream) @@ -126,42 +126,42 @@ extension ArgumentParser { } fileprivate func generateBashCasePrev(on stream: WritableByteStream) { - stream <<< " case $prev in\n" + stream.send(" case $prev in\n") for argument in optionArguments { let flags = [argument.name] + (argument.shortName.map({ [$0] }) ?? []) - stream <<< " (\(flags.joined(separator: "|")))\n" + stream.send(" (\(flags.joined(separator: "|")))\n") generateBashCompletion(argument, on: stream) - stream <<< " ;;\n" + stream.send(" ;;\n") } - stream <<< " esac\n" + stream.send(" esac\n") } fileprivate func generateBashCompletion(_ argument: AnyArgument, on stream: WritableByteStream) { switch argument.completion { case .none: // return; no value to complete - stream <<< " return\n" + stream.send(" return\n") case .unspecified: break case .values(let values): let x = values.map({ $0.value }).joined(separator: " ") - stream <<< """ + stream.send(""" COMPREPLY=( $(compgen -W "\(x)" -- $cur) ) return - """ + """) case .filename: - stream <<< """ + stream.send(""" _filedir return - """ + """) case .function(let name): - stream <<< """ + stream.send(""" \(name) return - """ + """) } } @@ -169,15 +169,15 @@ extension ArgumentParser { private func generateZshSwiftTool(name: String, on stream: WritableByteStream) { // Completions are provided by zsh's _arguments builtin. - stream <<< """ + stream.send(""" \(name)() { arguments=( - """ + """) for argument in positionalArguments { - stream <<< " \"" + stream.send(" \"") generateZshCompletion(argument, on: stream) - stream <<< "\"\n" + stream.send("\"\n") } for argument in optionArguments { generateZshArgument(argument, on: stream) @@ -185,58 +185,58 @@ extension ArgumentParser { // Use a simple state-machine when dealing with sub parsers. if subparsers.count > 0 { - stream <<< """ + stream.send(""" '(-): :->command' '(-)*:: :->arg' - """ + """) } - stream <<< """ + stream.send(""" ) _arguments $arguments && return - """ + """) // Handle the state set by the state machine. if subparsers.count > 0 { - stream <<< """ + stream.send(""" case $state in (command) local modes modes=( - """ + """) for (subName, subParser) in subparsers { - stream <<< """ + stream.send(""" '\(subName):\(subParser.overview)' - """ + """) } - stream <<< """ + stream.send(""" ) _describe "mode" modes ;; (arg) case ${words[1]} in - """ + """) for (subName, _) in subparsers { - stream <<< """ + stream.send(""" (\(subName)) \(name)_\(subName) ;; - """ + """) } - stream <<< """ + stream.send(""" esac ;; esac - """ + """) } - stream <<< "}\n\n" + stream.send("}\n\n") for (subName, subParser) in subparsers { subParser.generateZshSwiftTool(name: "\(name)_\(subName)", on: stream) @@ -245,10 +245,10 @@ extension ArgumentParser { /// Generates an option argument for `_arguments`, complete with description and completion values. fileprivate func generateZshArgument(_ argument: AnyArgument, on stream: WritableByteStream) { - stream <<< " \"" + stream.send(" \"") switch argument.shortName { - case .none: stream <<< "\(argument.name)" - case let shortName?: stream <<< "(\(argument.name) \(shortName))\"{\(argument.name),\(shortName)}\"" + case .none: stream.send("\(argument.name)") + case let shortName?: stream.send("(\(argument.name) \(shortName))\"{\(argument.name),\(shortName)}\"") } let description = removeDefaultRegex @@ -256,10 +256,10 @@ extension ArgumentParser { .replacingOccurrences(of: "\"", with: "\\\"") .replacingOccurrences(of: "[", with: "\\[") .replacingOccurrences(of: "]", with: "\\]") - stream <<< "[\(description)]" + stream.send("[\(description)]") generateZshCompletion(argument, on: stream) - stream <<< "\"\n" + stream.send("\"\n") } /// Generates completion values, as part of an item for `_arguments`. @@ -269,16 +269,16 @@ extension ArgumentParser { .replacingOccurrences(of: "\"", with: "\\\"") switch argument.completion { - case .none: stream <<< ":\(message): " + case .none: stream.send(":\(message): ") case .unspecified: break - case .filename: stream <<< ":\(message):_files" + case .filename: stream.send(":\(message):_files") case let .values(values): - stream <<< ": :{_values ''" + stream.send(": :{_values ''") for (value, description) in values { - stream <<< " '\(value)[\(description)]'" + stream.send(" '\(value)[\(description)]'") } - stream <<< "}" - case .function(let name): stream <<< ":\(message):\(name)" + stream.send("}") + case .function(let name): stream.send(":\(message):\(name)") } } } diff --git a/Sources/TSCUtility/Diagnostics.swift b/Sources/TSCUtility/Diagnostics.swift index 5b869044..8bd54548 100644 --- a/Sources/TSCUtility/Diagnostics.swift +++ b/Sources/TSCUtility/Diagnostics.swift @@ -208,9 +208,9 @@ public enum PackageLocation { public var description: String { let stream = BufferedOutputByteStream() if let name = name { - stream <<< "'\(name)' " + stream.send("'\(name)' ") } - stream <<< packagePath + stream.send(packagePath) return stream.bytes.description } } diff --git a/Sources/TSCUtility/ProgressAnimation.swift b/Sources/TSCUtility/ProgressAnimation.swift index 5651d814..c0383531 100644 --- a/Sources/TSCUtility/ProgressAnimation.swift +++ b/Sources/TSCUtility/ProgressAnimation.swift @@ -42,8 +42,8 @@ public final class SingleLinePercentProgressAnimation: ProgressAnimationProtocol public func update(step: Int, total: Int, text: String) { if let header = header, !hasDisplayedHeader { - stream <<< header - stream <<< "\n" + stream.send(header) + stream.send("\n") stream.flush() hasDisplayedHeader = true } @@ -51,7 +51,7 @@ public final class SingleLinePercentProgressAnimation: ProgressAnimationProtocol let percentage = step * 100 / total let roundedPercentage = Int(Double(percentage / 10).rounded(.down)) * 10 if percentage != 100, !displayedPercentages.contains(roundedPercentage) { - stream <<< String(roundedPercentage) <<< ".. " + stream.send(String(roundedPercentage)).send(".. ") displayedPercentages.insert(roundedPercentage) } @@ -60,7 +60,7 @@ public final class SingleLinePercentProgressAnimation: ProgressAnimationProtocol public func complete(success: Bool) { if success { - stream <<< "OK" + stream.send("OK") stream.flush() } } @@ -89,8 +89,8 @@ public final class MultiLineNinjaProgressAnimation: ProgressAnimationProtocol { guard text != lastDisplayedText else { return } - stream <<< "[\(step)/\(total)] " <<< text - stream <<< "\n" + stream.send("[\(step)/\(total)] ").send(text) + stream.send("\n") stream.flush() lastDisplayedText = text } @@ -171,15 +171,15 @@ public final class MultiLinePercentProgressAnimation: ProgressAnimationProtocol assert(step <= total) if !hasDisplayedHeader, !header.isEmpty { - stream <<< header - stream <<< "\n" + stream.send(header) + stream.send("\n") stream.flush() hasDisplayedHeader = true } let percentage = step * 100 / total - stream <<< "\(percentage)%: " <<< text - stream <<< "\n" + stream.send("\(percentage)%: ").send(text) + stream.send("\n") stream.flush() lastDisplayedText = text } diff --git a/Tests/TSCBasicPerformanceTests/SHA256PerfTests.swift b/Tests/TSCBasicPerformanceTests/SHA256PerfTests.swift index eeff7ee8..4709348d 100644 --- a/Tests/TSCBasicPerformanceTests/SHA256PerfTests.swift +++ b/Tests/TSCBasicPerformanceTests/SHA256PerfTests.swift @@ -20,7 +20,7 @@ class SHA256PerfTests: XCTestCasePerf { let byte = "f" let stream = BufferedOutputByteStream() for _ in 0..<20000 { - stream <<< byte + stream.send(byte) } measure { for _ in 0..<1000 { diff --git a/Tests/TSCBasicPerformanceTests/WritableByteStreamPerfTests.swift b/Tests/TSCBasicPerformanceTests/WritableByteStreamPerfTests.swift index aae8d8e5..c732b64a 100644 --- a/Tests/TSCBasicPerformanceTests/WritableByteStreamPerfTests.swift +++ b/Tests/TSCBasicPerformanceTests/WritableByteStreamPerfTests.swift @@ -51,7 +51,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<10 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 16) { - stream <<< sequence + stream.send(sequence) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -66,7 +66,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<10 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 20) { - stream <<< byte + stream.send(byte) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -80,7 +80,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<1 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 20) { - stream <<< Character("X") + stream.send(Character("X")) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -97,7 +97,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<100 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 16) { - stream <<< bytes16 + stream.send(bytes16) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -116,7 +116,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<100 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 16) { - stream <<< bytes16 + stream.send(bytes16) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -133,7 +133,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<1000 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 10) { - stream <<< bytes1k + stream.send(bytes1k) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -150,7 +150,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<10 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 16) { - stream <<< string16 + stream.send(string16) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -167,7 +167,7 @@ class OutputByteStreamPerfTests: XCTestCasePerf { for _ in 0..<100 { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 10) { - stream <<< bytes1k + stream.send(bytes1k) } XCTAssertEqual(stream.bytes.count, 1 << 20) } @@ -206,10 +206,10 @@ class OutputByteStreamPerfTests: XCTestCasePerf { let stream = BufferedOutputByteStream() for _ in 0..<(1 << 10) { for string in listOfStrings { - stream <<< Format.asJSON(string) + stream.send(Format.asJSON(string)) } - stream <<< Format.asJSON(listOfStrings) - stream <<< Format.asJSON(listOfThings, transform: { $0.value }) + stream.send(Format.asJSON(listOfStrings)) + stream.send(Format.asJSON(listOfThings, transform: { $0.value })) } XCTAssertGreaterThan(stream.bytes.count, 1000) } diff --git a/Tests/TSCBasicTests/ByteStringTests.swift b/Tests/TSCBasicTests/ByteStringTests.swift index 9fb665b2..3cada230 100644 --- a/Tests/TSCBasicTests/ByteStringTests.swift +++ b/Tests/TSCBasicTests/ByteStringTests.swift @@ -64,7 +64,7 @@ class ByteStringTests: XCTestCase { func testByteStreamable() { let s = BufferedOutputByteStream() - s <<< ByteString([1, 2, 3]) + s.send(ByteString([1, 2, 3])) XCTAssertEqual(s.bytes, [1, 2, 3]) } diff --git a/Tests/TSCBasicTests/FileSystemTests.swift b/Tests/TSCBasicTests/FileSystemTests.swift index 95b4910b..510bd430 100644 --- a/Tests/TSCBasicTests/FileSystemTests.swift +++ b/Tests/TSCBasicTests/FileSystemTests.swift @@ -48,12 +48,12 @@ class FileSystemTests: XCTestCase { let executableSym = tempDirPath.appending(component: "exec-sym") try! fs.createSymbolicLink(executableSym, pointingAt: executable, relative: false) let stream = BufferedOutputByteStream() - stream <<< """ + stream.send(""" #!/bin/sh set -e exit - """ + """) try! fs.writeFileContents(executable, bytes: stream.bytes) try! Process.checkNonZeroExit(args: "chmod", "+x", executable.pathString) XCTAssertTrue(fs.isExecutableFile(executable)) diff --git a/Tests/TSCBasicTests/ProcessTests.swift b/Tests/TSCBasicTests/ProcessTests.swift index 1e616a04..d9eb3aca 100644 --- a/Tests/TSCBasicTests/ProcessTests.swift +++ b/Tests/TSCBasicTests/ProcessTests.swift @@ -50,7 +50,7 @@ class ProcessTests: XCTestCase { try withTemporaryFile { file in let count = 10_000 let stream = BufferedOutputByteStream() - stream <<< Format.asRepeating(string: "a", count: count) + stream.send(Format.asRepeating(string: "a", count: count)) try localFileSystem.writeFileContents(file.path, bytes: stream.bytes) #if os(Windows) let cat = "cat.exe" diff --git a/Tests/TSCBasicTests/SHA256Tests.swift b/Tests/TSCBasicTests/SHA256Tests.swift index 396c658c..967bdfe7 100644 --- a/Tests/TSCBasicTests/SHA256Tests.swift +++ b/Tests/TSCBasicTests/SHA256Tests.swift @@ -32,7 +32,7 @@ class SHA256Tests: XCTestCase { let byte = "f" let stream = BufferedOutputByteStream() for _ in 0..<20000 { - stream <<< byte + stream.send(byte) } XCTAssertEqual(sha256.hash(stream.bytes).hexadecimalRepresentation, "23d00697ba26b4140869bab958431251e7e41982794d41b605b6a1d5dee56abf") } diff --git a/Tests/TSCBasicTests/TemporaryFileTests.swift b/Tests/TSCBasicTests/TemporaryFileTests.swift index 2d724673..de3c8197 100644 --- a/Tests/TSCBasicTests/TemporaryFileTests.swift +++ b/Tests/TSCBasicTests/TemporaryFileTests.swift @@ -26,9 +26,9 @@ class TemporaryFileTests: XCTestCase { // Try writing some data to the file. let stream = BufferedOutputByteStream() - stream <<< "foo" - stream <<< "bar" - stream <<< "baz" + stream.send("foo") + stream.send("bar") + stream.send("baz") try localFileSystem.writeFileContents(file.path, bytes: stream.bytes) // Go to the beginning of the file. @@ -50,9 +50,9 @@ class TemporaryFileTests: XCTestCase { // Try writing some data to the file. let stream = BufferedOutputByteStream() - stream <<< "foo" - stream <<< "bar" - stream <<< "baz" + stream.send("foo") + stream.send("bar") + stream.send("baz") try localFileSystem.writeFileContents(file.path, bytes: stream.bytes) // Go to the beginning of the file. diff --git a/Tests/TSCBasicTests/WritableByteStreamTests.swift b/Tests/TSCBasicTests/WritableByteStreamTests.swift index 2a12b904..e9b2eef4 100644 --- a/Tests/TSCBasicTests/WritableByteStreamTests.swift +++ b/Tests/TSCBasicTests/WritableByteStreamTests.swift @@ -34,7 +34,12 @@ class WritableByteStreamTests: XCTestCase { func testStreamOperator() { let stream = BufferedOutputByteStream() - stream <<< "Hello" <<< Character(",") <<< Character(" ") <<< [UInt8]("wor".utf8) <<< [UInt8]("world".utf8)[3..<5] + stream + .send("Hello") + .send(Character(",")) + .send(Character(" ")) + .send([UInt8]("wor".utf8)) + .send([UInt8]("world".utf8)[3..<5]) XCTAssertEqual(stream.position, "Hello, world".utf8.count) XCTAssertEqual(stream.bytes, "Hello, world") @@ -47,15 +52,15 @@ class WritableByteStreamTests: XCTestCase { let bigBlock = [UInt8](repeating: 1, count: blockSize) var stream = BufferedOutputByteStream() - stream <<< smallBlock <<< bigBlock + stream.send(smallBlock).send(bigBlock) XCTAssertEqual(stream.bytes, ByteString(smallBlock + bigBlock)) stream = BufferedOutputByteStream() - stream <<< bigBlock <<< smallBlock + stream.send(bigBlock).send(smallBlock) XCTAssertEqual(stream.bytes, ByteString(bigBlock + smallBlock)) stream = BufferedOutputByteStream() - stream <<< bigBlock <<< bigBlock + stream.send(bigBlock).send(bigBlock) XCTAssertEqual(stream.bytes, ByteString(bigBlock + bigBlock)) } } @@ -77,34 +82,34 @@ class WritableByteStreamTests: XCTestCase { // Test other random types. var stream = BufferedOutputByteStream() - stream <<< Format.asJSON(false) + stream.send(Format.asJSON(false)) XCTAssertEqual(stream.bytes, "false") stream = BufferedOutputByteStream() - stream <<< Format.asJSON(1 as Int) + stream .send(Format.asJSON(1 as Int)) XCTAssertEqual(stream.bytes, "1") stream = BufferedOutputByteStream() - stream <<< Format.asJSON(1.2 as Double) + stream.send(Format.asJSON(1.2 as Double)) XCTAssertEqual(stream.bytes, "1.2") } func testFormattedOutput() { do { let stream = BufferedOutputByteStream() - stream <<< Format.asJSON("\n") + stream.send(Format.asJSON("\n")) XCTAssertEqual(stream.bytes, "\"\\n\"") } do { let stream = BufferedOutputByteStream() - stream <<< Format.asJSON(["hello", "world\n"]) + stream.send(Format.asJSON(["hello", "world\n"])) XCTAssertEqual(stream.bytes, "[\"hello\",\"world\\n\"]") } do { let stream = BufferedOutputByteStream() - stream <<< Format.asJSON(["hello": "world\n"]) + stream.send(Format.asJSON(["hello": "world\n"])) XCTAssertEqual(stream.bytes, "{\"hello\":\"world\\n\"}") } @@ -114,13 +119,13 @@ class WritableByteStreamTests: XCTestCase { init(_ value: String) { self.value = value } } let stream = BufferedOutputByteStream() - stream <<< Format.asJSON([MyThing("hello"), MyThing("world\n")], transform: { $0.value }) + stream.send(Format.asJSON([MyThing("hello"), MyThing("world\n")], transform: { $0.value })) XCTAssertEqual(stream.bytes, "[\"hello\",\"world\\n\"]") } do { let stream = BufferedOutputByteStream() - stream <<< Format.asSeparatedList(["hello", "world"], separator: ", ") + stream.send(Format.asSeparatedList(["hello", "world"], separator: ", ")) XCTAssertEqual(stream.bytes, "hello, world") } @@ -130,25 +135,25 @@ class WritableByteStreamTests: XCTestCase { init(_ value: String) { self.value = value } } let stream = BufferedOutputByteStream() - stream <<< Format.asSeparatedList([MyThing("hello"), MyThing("world")], transform: { $0.value }, separator: ", ") + stream.send(Format.asSeparatedList([MyThing("hello"), MyThing("world")], transform: { $0.value }, separator: ", ")) XCTAssertEqual(stream.bytes, "hello, world") } do { var stream = BufferedOutputByteStream() - stream <<< Format.asRepeating(string: "foo", count: 1) + stream.send(Format.asRepeating(string: "foo", count: 1)) XCTAssertEqual(stream.bytes, "foo") stream = BufferedOutputByteStream() - stream <<< Format.asRepeating(string: "foo", count: 0) + stream.send(Format.asRepeating(string: "foo", count: 0)) XCTAssertEqual(stream.bytes, "") stream = BufferedOutputByteStream() - stream <<< Format.asRepeating(string: "x", count: 4) + stream.send(Format.asRepeating(string: "x", count: 4)) XCTAssertEqual(stream.bytes, "xxxx") stream = BufferedOutputByteStream() - stream <<< Format.asRepeating(string: "foo", count: 3) + stream.send(Format.asRepeating(string: "foo", count: 3)) XCTAssertEqual(stream.bytes, "foofoofoo") } } @@ -161,11 +166,11 @@ class WritableByteStreamTests: XCTestCase { } let stream = try LocalFileOutputByteStream(tempFile.path) - stream <<< "Hello" + stream.send("Hello") stream.flush() XCTAssertEqual(read(), "Hello") - stream <<< " World" + stream.send(" World") try stream.close() XCTAssertEqual(read(), "Hello World") @@ -196,7 +201,7 @@ class WritableByteStreamTests: XCTestCase { let t1 = Thread { for _ in 0..<1000 { - threadSafeStream <<< "Hello" + threadSafeStream.send("Hello") } } threads.append(t1) diff --git a/Tests/TSCUtilityTests/PkgConfigParserTests.swift b/Tests/TSCUtilityTests/PkgConfigParserTests.swift index 1c97bb74..7e4c3c7f 100644 --- a/Tests/TSCUtilityTests/PkgConfigParserTests.swift +++ b/Tests/TSCUtilityTests/PkgConfigParserTests.swift @@ -127,10 +127,10 @@ final class PkgConfigParserTests: XCTestCase { try localFileSystem.createDirectory(fakePkgConfig.parentDirectory) let stream = BufferedOutputByteStream() - stream <<< """ + stream.send(""" #!/bin/sh echo "/Volumes/BestDrive/pkgconfig" - """ + """) try localFileSystem.writeFileContents(fakePkgConfig, bytes: stream.bytes) // `FileSystem` does not support `chmod` on Linux, so we shell out instead. _ = try Process.popen(args: "chmod", "+x", fakePkgConfig.pathString) diff --git a/Tests/TSCUtilityTests/SimplePersistenceTests.swift b/Tests/TSCUtilityTests/SimplePersistenceTests.swift index f231fead..aea5cccd 100644 --- a/Tests/TSCUtilityTests/SimplePersistenceTests.swift +++ b/Tests/TSCUtilityTests/SimplePersistenceTests.swift @@ -183,7 +183,7 @@ class SimplePersistenceTests: XCTestCase { let fs = InMemoryFileSystem() let stateFile = AbsolutePath.root.appending(components: "subdir", "state.json") try fs.writeFileContents(stateFile) { - $0 <<< """ + $0.send(""" { "version": 0, "object": { @@ -191,7 +191,7 @@ class SimplePersistenceTests: XCTestCase { "old_int": 4 } } - """ + """) } let foo = Foo(int: 1, path: "/hello", fileSystem: fs)