Skip to content

Commit b8d3057

Browse files
committed
[CPFeature-003] Finished the working part, but still need some clean up
1 parent 2cc4096 commit b8d3057

File tree

11 files changed

+652
-127
lines changed

11 files changed

+652
-127
lines changed

Sources/CommitPrefix/CLIArguments.swift

Lines changed: 108 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -30,64 +30,110 @@ import SPMUtility
3030
public struct CLIArguments {
3131

3232
public enum UserCommand {
33-
case delete
34-
case view
35-
case newEntry(entry: String)
33+
case viewState
34+
case outputPrefixes
35+
case deletePrefixes
36+
case modeNormal
37+
case modeBranchParse(validator: String)
38+
case newPrefixes(value: String)
39+
}
40+
41+
private enum ParsedCommand {
42+
case viewState
43+
case outputPrefixes
44+
case deletePrefixes
45+
case modeNormal
46+
case modeBranchParse
47+
case userEntry(value: String)
3648
}
3749

3850
private let parser: ArgumentParser
3951
private let rawArgs: [String]
4052

41-
private let delete: OptionArgument<Bool>
42-
private let view: OptionArgument<Bool>
43-
private let newEntry: PositionalArgument<[String]>
53+
private let outputPrefixes: OptionArgument<Bool>
54+
private let deletePrefixes: OptionArgument<Bool>
55+
private let modeNormal: OptionArgument<Bool>
56+
private let modeBranchParse: OptionArgument<Bool>
57+
private let userEntry: PositionalArgument<[String]>
4458

4559
public init(arguments: [String] = CommandLine.arguments) {
4660
// The first argument specifies the path of the executable file
4761
self.rawArgs = Array(arguments.dropFirst())
4862
let argBuilder = ArgumentBuilder()
4963
self.parser = argBuilder.buildParser()
50-
self.delete = argBuilder.buildDeleteArgument(parser: parser)
51-
self.view = argBuilder.buildViewArgument(parser: parser)
52-
self.newEntry = argBuilder.buildNewEntryArgument(parser: parser)
64+
65+
self.outputPrefixes = argBuilder.buildOutputArgument(parser: parser)
66+
self.deletePrefixes = argBuilder.buildDeleteArgument(parser: parser)
67+
self.modeNormal = argBuilder.buildNormalArgument(parser: parser)
68+
self.modeBranchParse = argBuilder.buildBranchParseArgument(parser: parser)
69+
self.userEntry = argBuilder.buildUserEntryArgument(parser: parser)
5370
}
5471

72+
private func singleCommandParse(_ allCommands: [ParsedCommand]) throws -> UserCommand {
73+
precondition(allCommands.count == 1, "Intended for single Parsed Command only!")
74+
guard let foundCommand = allCommands.first else {
75+
throw CPError.userCommandNotRecognized
76+
}
77+
78+
switch foundCommand {
79+
case .outputPrefixes:
80+
return .outputPrefixes
81+
case .deletePrefixes:
82+
return .deletePrefixes
83+
case .modeNormal:
84+
return .modeNormal
85+
case .userEntry(value: let prefixes):
86+
return .newPrefixes(value: prefixes)
87+
default:
88+
throw CPError.userCommandNotRecognized
89+
}
90+
}
91+
92+
private func doubleCommandParse(_ allCommands: [ParsedCommand]) throws -> UserCommand {
93+
precondition(allCommands.count == 2, "Intended for two Parsed Commands only!")
94+
let firstCommand = allCommands[0]
95+
let secondCommand = allCommands[1]
96+
97+
switch (firstCommand, secondCommand) {
98+
case (.modeBranchParse, .userEntry(value: let validator)):
99+
return .modeBranchParse(validator: validator)
100+
case (.userEntry(value: let validator), .modeBranchParse):
101+
return .modeBranchParse(validator: validator)
102+
default:
103+
throw CPError.userCommandNotRecognized
104+
}
105+
}
106+
55107
func getCommand() throws -> UserCommand {
56108
guard let parsedArgs = try? parser.parse(rawArgs) else {
57109
throw CPError.userCommandNotRecognized
58110
}
59111

60-
var allCommands = [UserCommand]()
112+
var allCommands = [ParsedCommand]()
61113

62-
parsedArgs.get(delete).map { _ in allCommands.append(.delete) }
63-
parsedArgs.get(view).map { _ in allCommands.append(.view) }
64-
try parsedArgs.get(newEntry).map { userEntry in
65-
66-
guard userEntry.count < 2 else {
67-
throw CPError.newEntryShouldNotHaveSpaces
68-
}
69-
70-
guard let theEntry = userEntry.first else {
71-
throw CPError.emptyEntry
72-
}
73-
74-
guard !theEntry.isEmpty else {
75-
throw CPError.emptyEntry
76-
}
77-
78-
allCommands.append(.newEntry(entry: theEntry))
79-
80-
}
114+
parsedArgs.get(outputPrefixes).map { _ in allCommands.append(.outputPrefixes) }
115+
parsedArgs.get(deletePrefixes).map { _ in allCommands.append(.deletePrefixes) }
116+
parsedArgs.get(modeNormal).map { _ in allCommands.append(.modeNormal) }
117+
parsedArgs.get(modeBranchParse).map { _ in allCommands.append(.modeBranchParse) }
81118

82-
guard allCommands.count < 2 else {
83-
throw CPError.multipleArguments
119+
try parsedArgs.get(userEntry).map { userEntry in
120+
let noMoreThanOneEntry = userEntry.count < 2
121+
guard noMoreThanOneEntry else { throw CPError.newEntryShouldNotHaveSpaces }
122+
guard let theEntry = userEntry.first else { throw CPError.emptyEntry }
123+
allCommands.append(.userEntry(value: theEntry))
84124
}
85125

86-
guard let command = allCommands.first else {
87-
throw CPError.userCommandNotRecognized
126+
switch allCommands.count {
127+
case 0:
128+
return .viewState
129+
case 1:
130+
return try singleCommandParse(allCommands)
131+
case 2:
132+
return try doubleCommandParse(allCommands)
133+
default:
134+
throw CPError.multipleArguments
88135
}
89136

90-
return command
91137
}
92138

93139
}
@@ -108,30 +154,50 @@ private struct ArgumentBuilder {
108154
func buildParser() -> ArgumentParser {
109155
ArgumentParser(usage: usage, overview: overview)
110156
}
111-
157+
158+
func buildOutputArgument(parser: ArgumentParser) -> OptionArgument<Bool> {
159+
return parser.add(
160+
option: "--output",
161+
shortName: "-o",
162+
kind: Bool.self,
163+
usage: "Outputs the full, formated prefix to standard output",
164+
completion: nil
165+
)
166+
}
167+
112168
func buildDeleteArgument(parser: ArgumentParser) -> OptionArgument<Bool> {
113169
return parser.add(
114170
option: "--delete",
115171
shortName: "-d",
116172
kind: Bool.self,
117-
usage: "Deletes the stored prefix",
173+
usage: "Deletes the stored prefixes",
118174
completion: nil
119175
)
120176
}
121177

122-
func buildViewArgument(parser: ArgumentParser) -> OptionArgument<Bool> {
178+
func buildNormalArgument(parser: ArgumentParser) -> OptionArgument<Bool> {
179+
return parser.add(
180+
option: "--normal",
181+
shortName: "-n",
182+
kind: Bool.self,
183+
usage: "Sets the mode to NORMAL",
184+
completion: nil
185+
)
186+
}
187+
188+
func buildBranchParseArgument(parser: ArgumentParser) -> OptionArgument<Bool> {
123189
return parser.add(
124-
option: "--view",
125-
shortName: "-v",
190+
option: "--branchParse",
191+
shortName: "-b",
126192
kind: Bool.self,
127-
usage: "Display the currently stored prefix",
193+
usage: "Sets the mode to BRANCH_PARSE. Requires a validator",
128194
completion: nil
129195
)
130196
}
131197

132-
func buildNewEntryArgument(parser: ArgumentParser) -> PositionalArgument<[String]> {
198+
func buildUserEntryArgument(parser: ArgumentParser) -> PositionalArgument<[String]> {
133199
return parser.add(
134-
positional: "NewEntry",
200+
positional: "UserEntry",
135201
kind: [String].self,
136202
optional: true,
137203
usage: nil,

Sources/CommitPrefix/CPDebugPrint.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ private let isDebugMode = false
3535
/// A Debug Printer that only prints in debug mode
3636
public func cpDebugPrint(_ value: Any, file: String = #file, line: Int = #line, function: String = #function) {
3737
guard isDebugMode else { return }
38-
print("/n", "********** Commit Prefix Debug **********")
38+
print("********** Commit Prefix Debug **********")
3939
print("File: \(file)")
4040
print("Line: \(line)")
4141
print("Function: \(function)")
4242
print("value: ", value)
43-
print("*****************************************", "/n")
43+
print("*****************************************")
4444
}

Sources/CommitPrefix/CPError.swift

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ enum CPError: Error {
3636
case fileReadWriteError
3737
case directoryNotFound(name: String, path: String)
3838
case hookReadWriteError
39-
case expectedYesOrNo
39+
case branchValidatorFormatError
4040

4141
var message: String {
4242
switch self {
@@ -47,7 +47,7 @@ enum CPError: Error {
4747
case .emptyEntry:
4848
return "Your entry is empty."
4949
case .multipleArguments:
50-
return "Multiple arguments entered. Only one at a time is supported."
50+
return "Too many arguments entered. Only two at a time is supported."
5151
case .notAGitRepo(currentLocation: let location):
5252
return "Not in a git repo or at the root of one: \(location)"
5353
case .fileReadWriteError:
@@ -56,8 +56,35 @@ enum CPError: Error {
5656
return "Directory named \(name) was not found at \(path)"
5757
case .hookReadWriteError:
5858
return "An error occured while reading or writing to the commit-msg hook"
59+
case .branchValidatorFormatError:
60+
return "The branch validator must be at least two characters long "
61+
+ "and contain no numbers or spaces"
62+
}
63+
64+
}
65+
66+
}
67+
68+
enum CPTermination: Error {
69+
70+
case overwriteCancelled
71+
case expectedYesOrNo
72+
case branchValidatorNotPresent
73+
case invalidBranchPrefix(validator: String)
74+
75+
var message: String {
76+
switch self {
77+
case .overwriteCancelled:
78+
return "Overwrite is cancelled"
5979
case .expectedYesOrNo:
60-
return "expected y or n. The transaction has been cancelled."
80+
return "Expected y or n. The transaction has been cancelled."
81+
case .branchValidatorNotPresent:
82+
return "Attempting to provide a branch prefix without a branch validator"
83+
case .invalidBranchPrefix(validator: let validator):
84+
return """
85+
Your branch does not begin with \(validator) and is invalid.
86+
Either change your branch name or use commitPrefix in non-branch mode.
87+
"""
6188
}
6289

6390
}

Sources/CommitPrefix/CPFileHandler.swift

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,51 +29,52 @@ import Files
2929

3030
public struct CPFileHandler {
3131

32-
private let commitPrefixFile: File
33-
private let commitMessageHook: CommitMessageHook
32+
private let cpInteractor: CPInteractor
3433

3534
public init() throws {
36-
let currentDirectory = Folder.current
37-
let correctLocation = currentDirectory.containsSubfolder(named: FolderName.git)
38-
guard correctLocation else {
39-
throw CPError.notAGitRepo(currentLocation: currentDirectory.path)
35+
guard Folder.current.containsSubfolder(named: FolderName.git) else {
36+
throw CPError.notAGitRepo(currentLocation: Folder.current.path)
4037
}
41-
let gitDirectory = try currentDirectory.subfolder(named: FolderName.git)
42-
self.commitPrefixFile = try gitDirectory.createFileIfNeeded(withName: FileName.commitPrefix)
43-
self.commitMessageHook = try CommitMessageHook(gitDirectory: gitDirectory)
38+
let gitDirectory = try Folder.current.subfolder(named: FolderName.git)
39+
self.cpInteractor = try CPInteractor(gitDirectory: gitDirectory)
40+
try CommitMessageHook.findOrCreate(with: gitDirectory)
4441
}
4542

46-
public func locateOrCreateHook() throws {
47-
try commitMessageHook.locateOrCreateHook()
43+
public func outputPrefixes() throws -> String {
44+
try cpInteractor.outputPrefixes()
4845
}
4946

50-
public func outputPrefix() throws -> String {
51-
let contents = try? commitPrefixFile.readAsString(encodedAs: .utf8)
52-
guard let readContents = contents else {
53-
throw CPError.fileReadWriteError
47+
public func viewState() throws -> String {
48+
let cpState = try cpInteractor.getCommitPrefixState()
49+
switch cpState.mode {
50+
case .normal:
51+
return """
52+
CommitPrefix MODE NORMAL
53+
- prefixes: \(cpState.normalPrefixes.joined())
54+
"""
55+
case .branchParse:
56+
return """
57+
CommitPrefix MODE BRANCH_PARSE
58+
- branch prefixes: \(cpState.branchPrefixes.joined())
59+
- stored prefixes: \(cpState.normalPrefixes.joined())
60+
"""
5461
}
55-
return readContents
5662
}
5763

58-
public func deletePrefix() throws -> String {
59-
do {
60-
try commitPrefixFile.write("", encoding: .utf8)
61-
} catch {
62-
throw CPError.fileReadWriteError
63-
}
64-
return "CommitPrefix Deleted"
64+
public func deletePrefixes() throws -> String {
65+
try cpInteractor.deletePrefixes()
6566
}
6667

67-
public func writeNew(prefix: String) throws -> String {
68-
let bracketSet = CharacterSet(charactersIn: "[]")
69-
let debracketedPrefix = prefix.trimmingCharacters(in: bracketSet)
70-
let formattedPrefix = "[\(debracketedPrefix)]"
71-
do {
72-
try commitPrefixFile.write(formattedPrefix, encoding: .utf8)
73-
} catch {
74-
throw CPError.fileReadWriteError
75-
}
76-
return formattedPrefix
68+
public func writeNew(prefixes rawValue: String) throws -> String {
69+
try cpInteractor.writeNew(prefixes: rawValue)
70+
}
71+
72+
public func activateBranchMode(with validator: String) throws -> String {
73+
try cpInteractor.activateBranchMode(with: validator)
74+
}
75+
76+
public func activateNormalMode() throws -> String {
77+
try cpInteractor.activateNormalMode()
7778
}
7879

7980
}

0 commit comments

Comments
 (0)