From 54ed71f55fb593170edb91766295413b523cba65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Ha=CC=8Ard?= Date: Wed, 9 Sep 2020 13:45:25 +0200 Subject: [PATCH 1/5] Updated project.pbxproj to SWIFT_VERSION 5.0 --- AbandonedStrings.xcodeproj/project.pbxproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AbandonedStrings.xcodeproj/project.pbxproj b/AbandonedStrings.xcodeproj/project.pbxproj index f37ef55..07e73c5 100644 --- a/AbandonedStrings.xcodeproj/project.pbxproj +++ b/AbandonedStrings.xcodeproj/project.pbxproj @@ -103,6 +103,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = 0361F1331C605FE0009D519A; @@ -211,7 +212,7 @@ isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -219,7 +220,7 @@ isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; }; name = Release; }; From a0863e5e999ca80ef3a25b3dde077db336c889a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Ha=CC=8Ard?= Date: Wed, 9 Sep 2020 13:45:49 +0200 Subject: [PATCH 2/5] FIxed compiler warnings for Swift 5 --- AbandonedStrings/main.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AbandonedStrings/main.swift b/AbandonedStrings/main.swift index 9fffaa8..6c710ce 100755 --- a/AbandonedStrings/main.swift +++ b/AbandonedStrings/main.swift @@ -73,7 +73,7 @@ func extractStringIdentifiersFrom(_ stringsFile: String) -> [String] { func extractStringIdentifierFromTrimmedLine(_ line: String) -> String { let indexAfterFirstQuote = line.index(after: line.startIndex) let lineWithoutFirstQuote = line[indexAfterFirstQuote...] - let endIndex = lineWithoutFirstQuote.index(of:"\"")! + let endIndex = lineWithoutFirstQuote.firstIndex(of:"\"")! let identifier = lineWithoutFirstQuote[.. [String]? { c.removeLast() } if isOptionaParameterForWritingAvailable() { - c.remove(at: c.index(of: "write")!) + c.remove(at: c.firstIndex(of: "write")!) } return c } From 6f2e33ff5e96b282cb9ec65989cb8bb305e2aae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Ha=CC=8Ard?= Date: Wed, 9 Sep 2020 13:47:34 +0200 Subject: [PATCH 3/5] Updated project.pbxproj to recommended project settings --- AbandonedStrings.xcodeproj/project.pbxproj | 27 +++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/AbandonedStrings.xcodeproj/project.pbxproj b/AbandonedStrings.xcodeproj/project.pbxproj index 07e73c5..b1d21fa 100644 --- a/AbandonedStrings.xcodeproj/project.pbxproj +++ b/AbandonedStrings.xcodeproj/project.pbxproj @@ -89,7 +89,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 1160; ORGANIZATIONNAME = iJoshSmith; TargetAttributes = { 0361F13B1C605FE0009D519A = { @@ -132,17 +132,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -176,17 +187,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "-"; @@ -205,12 +227,14 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; }; name = Release; }; 0361F1441C605FE0009D519A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "-"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; @@ -219,6 +243,7 @@ 0361F1451C605FE0009D519A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "-"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; }; From a3046e3653befe5a7252dc4b7138d84e44e6a577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Ha=CC=8Ard?= Date: Wed, 9 Sep 2020 14:00:04 +0200 Subject: [PATCH 4/5] Write to stdout and stderr instead of using print and NSLog --- AbandonedStrings.xcodeproj/project.pbxproj | 4 ++ AbandonedStrings/OutputStream.swift | 56 ++++++++++++++++++++++ AbandonedStrings/main.swift | 28 ++++++----- 3 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 AbandonedStrings/OutputStream.swift diff --git a/AbandonedStrings.xcodeproj/project.pbxproj b/AbandonedStrings.xcodeproj/project.pbxproj index b1d21fa..a20868c 100644 --- a/AbandonedStrings.xcodeproj/project.pbxproj +++ b/AbandonedStrings.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 0361F1401C605FE0009D519A /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0361F13F1C605FE0009D519A /* main.swift */; }; + E1FCEFA92508F93C00B1138C /* OutputStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1FCEFA82508F93C00B1138C /* OutputStream.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -25,6 +26,7 @@ /* Begin PBXFileReference section */ 0361F13C1C605FE0009D519A /* AbandonedStrings */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = AbandonedStrings; sourceTree = BUILT_PRODUCTS_DIR; }; 0361F13F1C605FE0009D519A /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + E1FCEFA82508F93C00B1138C /* OutputStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputStream.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -58,6 +60,7 @@ isa = PBXGroup; children = ( 0361F13F1C605FE0009D519A /* main.swift */, + E1FCEFA82508F93C00B1138C /* OutputStream.swift */, ); path = AbandonedStrings; sourceTree = ""; @@ -121,6 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E1FCEFA92508F93C00B1138C /* OutputStream.swift in Sources */, 0361F1401C605FE0009D519A /* main.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/AbandonedStrings/OutputStream.swift b/AbandonedStrings/OutputStream.swift new file mode 100644 index 0000000..ffbea06 --- /dev/null +++ b/AbandonedStrings/OutputStream.swift @@ -0,0 +1,56 @@ +// +// OutputStream.swift +// AbandonedStrings +// +// Created by Andreas Hård on 2020-09-09. +// Copyright © 2020 iJoshSmith. All rights reserved. +// + +import Foundation + +enum OutputStreamType { + case stdOut + case stdErr + + var fileHandle: FileHandle { + switch self { + case .stdOut: + return FileHandle.standardOutput + case .stdErr: + return FileHandle.standardError + } + } +} + +struct OutputStream: TextOutputStream { + let stringEncoding: String.Encoding + let streamType: OutputStreamType + + init(streamType: OutputStreamType, + stringEncoding: String.Encoding) { + self.streamType = streamType + self.stringEncoding = stringEncoding + } + + func write(_ string: String) { + guard let data = string.data(using: stringEncoding) else { + let errorString: String = "Failed to convert string: \"\(string)\" to Data using string encoding: \"\(stringEncoding)\"" + forceWriteToStdErr(errorString) + return + } + + streamType.fileHandle.write(data) + } + + func forceWriteToStdErr(_ string: String) { + guard let data = string.data(using: stringEncoding) else { + fatalError("Failed to write to stderr with string: \(string)") + } + switch streamType { + case .stdErr: + streamType.fileHandle.write(data) + case .stdOut: + FileHandle.standardError.write(data) + } + } +} diff --git a/AbandonedStrings/main.swift b/AbandonedStrings/main.swift index 6c710ce..5c62232 100755 --- a/AbandonedStrings/main.swift +++ b/AbandonedStrings/main.swift @@ -17,13 +17,15 @@ import Foundation let dispatchGroup = DispatchGroup.init() let serialWriterQueue = DispatchQueue.init(label: "writer") +let standardOut: OutputStream = OutputStream(streamType: .stdOut, stringEncoding: .utf8) +let standardError: OutputStream = OutputStream(streamType: .stdErr, stringEncoding: .utf8) func findFilesIn(_ directories: [String], withExtensions extensions: [String]) -> [String] { let fileManager = FileManager.default var files = [String]() for directory in directories { guard let enumerator: FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: directory) else { - print("Failed to create enumerator for directory: \(directory)") + standardError.write("Failed to create enumerator for directory: \(directory)") return [] } while let path = enumerator.nextObject() as? String { @@ -41,8 +43,8 @@ func contentsOfFile(_ filePath: String) -> String { do { return try String(contentsOfFile: filePath) } - catch { - print("cannot read file!!!") + catch { + standardError.forceWriteToStdErr("Cannot find file at path: \(filePath)") exit(1) } } @@ -118,7 +120,7 @@ func findAbandonedIdentifiersIn(_ rootDirectories: [String], withStoryboard: Boo dispatchGroup.leave() } } else { - NSLog("\(stringsFile) has no abandonedIdentifiers") + standardOut.write("\(stringsFile) has no abandonedIdentifiers") dispatchGroup.leave() } } @@ -154,37 +156,37 @@ func isOptionaParameterForWritingAvailable() -> Bool { func displayAbandonedIdentifiersInMap(_ map: StringsFileToAbandonedIdentifiersMap) { for file in map.keys.sorted() { - print("\(file)") + standardOut.write("\(file)") for identifier in map[file]!.sorted() { - print(" \(identifier)") + standardOut.write(" \(identifier)") } - print("") + standardOut.write("") } } if let rootDirectories = getRootDirectories() { - print("Searching for abandoned resource strings…") + standardOut.write("Searching for abandoned resource strings…") let withStoryboard = isOptionalParameterForStoryboardAvailable() let map = findAbandonedIdentifiersIn(rootDirectories, withStoryboard: withStoryboard) if map.isEmpty { - print("No abandoned resource strings were detected.") + standardOut.write("No abandoned resource strings were detected.") } else { - print("Abandoned resource strings were detected:") + standardOut.write("Abandoned resource strings were detected:") displayAbandonedIdentifiersInMap(map) if isOptionaParameterForWritingAvailable() { map.keys.forEach { (stringsFilePath) in - print("\n\nNow modifying \(stringsFilePath) ...") + standardOut.write("\n\nNow modifying \(stringsFilePath) ...") let updatedStringsFileContent = stringsFile(stringsFilePath, without: map[stringsFilePath]!) do { try updatedStringsFileContent.write(toFile: stringsFilePath, atomically: true, encoding: .utf8) } catch { - print("ERROR writing file: \(stringsFilePath)") + standardError.write("ERROR writing file: \(stringsFilePath)") } } } } } else { - print("Please provide the root directory for source code files as a command line argument.") + standardOut.write("Please provide the root directory for source code files as a command line argument.") } From 7e4b80bd4c5de78aaf1042dcdc2c85e792d6b0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Ha=CC=8Ard?= Date: Wed, 9 Sep 2020 16:07:21 +0200 Subject: [PATCH 5/5] Appending new lines to given strings in OutputStream.swift --- AbandonedStrings/OutputStream.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AbandonedStrings/OutputStream.swift b/AbandonedStrings/OutputStream.swift index ffbea06..9a84306 100644 --- a/AbandonedStrings/OutputStream.swift +++ b/AbandonedStrings/OutputStream.swift @@ -33,8 +33,9 @@ struct OutputStream: TextOutputStream { } func write(_ string: String) { - guard let data = string.data(using: stringEncoding) else { - let errorString: String = "Failed to convert string: \"\(string)\" to Data using string encoding: \"\(stringEncoding)\"" + let outputString: String = "\(string)\n" + guard let data = outputString.data(using: stringEncoding) else { + let errorString: String = "Failed to convert string: \"\(string)\" to Data using string encoding: \"\(stringEncoding)\"\n" forceWriteToStdErr(errorString) return } @@ -44,7 +45,7 @@ struct OutputStream: TextOutputStream { func forceWriteToStdErr(_ string: String) { guard let data = string.data(using: stringEncoding) else { - fatalError("Failed to write to stderr with string: \(string)") + fatalError("Failed to write to stderr with string: \(string)\n") } switch streamType { case .stdErr: