Skip to content

Commit 52122f7

Browse files
committed
feat: new array based API for git commands through webui
1 parent 247bc5d commit 52122f7

File tree

4 files changed

+223
-41
lines changed

4 files changed

+223
-41
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [2.4.1] - Unreleased
99

10+
### Added
11+
- New API endpoint that accepts git commands as array instead of string (#437)
12+
1013
### Fixed
1114
- Fixed JS errors in Studio on certain operations (#416)
1215
- Add menu option disabled for unsaved files (#420)

cls/SourceControl/Git/WebUIDriver.cls

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
2727
if $isobject($get(responseJSON)) {
2828
do responseJSON.%ToJSON(%data)
2929
}
30-
} elseif $match(pathStart,"git|dirname|hostname|viewonly") {
30+
} elseif $match(pathStart,"git-command|git|dirname|hostname|viewonly") {
3131
if (%request.Method = "GET") {
3232
set %data = ##class(%Stream.TmpCharacter).%New()
3333
// Things not handled from Python backend:
@@ -159,9 +159,40 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
159159
do ##class(SourceControl.Git.Change).RefreshUncommitted(,,,1)
160160
}
161161
set handled = 1
162-
} elseif (pathStart = "newgit") {
163-
merge data = %request.Data
162+
} elseif (pathStart = "git-command") {
163+
set requestBody = ##class(%Library.DynamicObject).%FromJSON(%request.Content)
164+
set command = requestBody.command
165+
166+
set argsArr = ""
167+
set argsArr($increment(argsArr)) = "color.ui=true"
168+
set iterator = command.%GetIterator()
169+
while iterator.%GetNext(,.value) {
170+
set argsArr($increment(argsArr)) = value
171+
}
172+
173+
set inFile = ""
174+
175+
set returnCode = ##class(SourceControl.Git.Utils).RunGitCommandWithInput("-c", inFile, .errStream, .outStream, argsArr...)
176+
set %data = ##class(%Stream.TmpCharacter).%New()
177+
set changeTerminators = (%data.LineTerminator '= $char(13,10))
178+
set %data.LineTerminator = $char(13,10) // For the CSPGateway.
179+
while 'outStream.AtEnd {
180+
do %data.WriteLine(outStream.ReadLine())
181+
}
182+
183+
set nLines = 0
184+
while 'errStream.AtEnd {
185+
do %data.WriteLine(errStream.ReadLine())
186+
set:changeTerminators nLines = nLines + 1
187+
}
164188

189+
// Need to write out two lines or we get an infinite loop in JavaScript...
190+
do %data.WriteLine()
191+
do %data.WriteLine()
192+
do %data.WriteLine("Git-Stderr-Length: " _ (errStream.Size + nLines))
193+
do %data.Write("Git-Return-Code: " _ returnCode) // No ending newline expected
194+
do %data.Rewind()
195+
set handled = 1
165196
}
166197
}
167198
}

git-webui/release/share/git-webui/webui/js/git-webui.js

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,89 @@ webui.showWarning = function(message) {
110110
'</div>').appendTo(messageBox);
111111
}
112112

113+
webui.git_command = function(command, callback) {
114+
$.ajax({
115+
url: "git-command",
116+
type: "POST",
117+
contentType: 'application/json',
118+
data: JSON.stringify({
119+
command: command
120+
}),
121+
success: function(data) {
122+
// Convention : last lines are footer meta data like headers. An empty line marks the start if the footers
123+
var footers = {};
124+
var fIndex = data.length;
125+
while (true) {
126+
var oldFIndex = fIndex;
127+
fIndex = data.lastIndexOf("\r\n", fIndex - 1);
128+
var line = data.substring(fIndex + 2, oldFIndex);
129+
if (line.length > 0) {
130+
var footer = line.split(": ");
131+
footers[footer[0]] = footer[1];
132+
} else {
133+
break;
134+
}
135+
}
136+
// Trims the the data variable to remove the footers extracted in the loop.
137+
// Windows adds \r\n for every line break but the Git-Stderr-Length variable,
138+
// counts it as only one character, throwing off the message length.
139+
var trimmedData = data.substring(0, fIndex).replace(/(\r\n)/gm, "\n");
140+
var fIndex = trimmedData.length
141+
142+
var messageLength = parseInt(footers["Git-Stderr-Length"]);
143+
var messageStartIndex = fIndex-messageLength;
144+
var message = trimmedData.substring(messageStartIndex, fIndex);
145+
146+
var output = trimmedData.substring(0, messageStartIndex);
147+
var rcode = parseInt(footers["Git-Return-Code"]);
148+
149+
if (rcode == 0) {
150+
if (callback) {
151+
callback(output);
152+
}
153+
// Return code is 0 but there is stderr output: this is a warning message
154+
if (message.length > 0) {
155+
if(warningCallback) {
156+
warningCallback(message);
157+
} else {
158+
webui.showWarning(message);
159+
}
160+
}
161+
} else {
162+
var displayMessage = ""
163+
if(output.length > 0){
164+
displayMessage += (output+"\n");
165+
}
166+
if(message.length > 0){
167+
displayMessage += message;
168+
}
169+
if(displayMessage.length > 0){
170+
// if(errorCallback) {
171+
// errorCallback(displayMessage);
172+
// } else{
173+
if(displayMessage.indexOf("self.document.Login") != -1){
174+
location.reload();
175+
return false;
176+
}
177+
webui.showError(displayMessage);
178+
//}
179+
} else {
180+
webui.showError("The command <pre>"+command.join(" ")+"</pre> failed because of an unknown reason. Returned response: \n\n"+data)
181+
}
182+
}
183+
},
184+
error: function(data) {
185+
var trimmedData = data.substring(0, fIndex).replace(/(\r\n)/gm, "\n");
186+
var fIndex = trimmedData.length
187+
188+
var messageLength = parseInt(footers["Git-Stderr-Length"]);
189+
var messageStartIndex = fIndex-messageLength;
190+
var message = trimmedData.substring(messageStartIndex, fIndex);
191+
webui.showError(message);
192+
},
193+
});
194+
}
195+
113196
webui.git = function(cmd, arg1, arg2, arg3, arg4) {
114197
// cmd = git command line arguments
115198
// other arguments = optional stdin content and a callback function.
@@ -2551,42 +2634,33 @@ webui.NewChangedFilesView = function(workspaceView) {
25512634

25522635
self.amend = function(message, details) {
25532636
var selectedFilesAsString = selectedItems.join(" ");
2554-
message = self.doubleQuotesToSingleQuotes(message);
2555-
details = self.doubleQuotesToSingleQuotes(details);
25562637

25572638
if (self.commitMsgEmpty()) {
2558-
webui.git("add " + selectedFilesAsString);
2559-
webui.git("commit --amend --no-edit -- " + selectedFilesAsString, function(output) {
2639+
webui.git_command(['add', selectedFilesAsString]);
2640+
webui.git_command(['commit', '--amend', '--no-edit', '--', selectedFilesAsString], function(output) {
25602641
webui.showSuccess(output);
25612642
workspaceView.update();
2562-
})
2643+
});
25632644
} else if (selectedItems.length != 0) {
2564-
webui.git("add " + selectedFilesAsString);
2565-
webui.git('commit --amend -m "' + message + '" -m "' + details + '" -- ' + selectedFilesAsString, function(output) {
2645+
webui.git_command(['add', selectedFilesAsString]);
2646+
webui.git_command(['commit', '--amend', '-m', message, '-m', 'details', '--', selectedFilesAsString], function(output) {
25662647
webui.showSuccess(output);
25672648
workspaceView.update();
2568-
})
2649+
});
25692650
} else {
2570-
webui.git('commit --amend --allow-empty -m "' + message + '" -m "' + details + '"', function(output) {
2651+
webui.git_command(['commit', '--amend', '--allow-empty', '-m', message, '-m', details], function(output) {
25712652
webui.showSuccess(output);
25722653
workspaceView.update();
2573-
})
2654+
});
25742655
}
25752656

25762657

25772658
}
25782659

2579-
self.doubleQuotesToSingleQuotes = function(string) {
2580-
return string.replace(/"/g, "'");
2581-
}
2582-
25832660
self.commit = function(message, details) {
25842661
var selectedFilesAsString = selectedItems.join(" ");
2585-
message = self.doubleQuotesToSingleQuotes(message);
2586-
details = self.doubleQuotesToSingleQuotes(details);
2587-
2588-
webui.git("add " + selectedFilesAsString);
2589-
webui.git('commit -m "' + message + '" -m "' + details + '" -- ' + selectedFilesAsString, function(output) {
2662+
webui.git_command(['add', selectedFilesAsString]);
2663+
webui.git_command(['commit', '-m', message, '-m', details, '--', selectedFilesAsString], function(output) {
25902664
webui.showSuccess(output);
25912665
workspaceView.update();
25922666
});

git-webui/src/share/git-webui/webui/js/git-webui.js

Lines changed: 93 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,89 @@ webui.showWarning = function(message) {
110110
'</div>').appendTo(messageBox);
111111
}
112112

113+
webui.git_command = function(command, callback) {
114+
$.ajax({
115+
url: "git-command",
116+
type: "POST",
117+
contentType: 'application/json',
118+
data: JSON.stringify({
119+
command: command
120+
}),
121+
success: function(data) {
122+
// Convention : last lines are footer meta data like headers. An empty line marks the start if the footers
123+
var footers = {};
124+
var fIndex = data.length;
125+
while (true) {
126+
var oldFIndex = fIndex;
127+
fIndex = data.lastIndexOf("\r\n", fIndex - 1);
128+
var line = data.substring(fIndex + 2, oldFIndex);
129+
if (line.length > 0) {
130+
var footer = line.split(": ");
131+
footers[footer[0]] = footer[1];
132+
} else {
133+
break;
134+
}
135+
}
136+
// Trims the the data variable to remove the footers extracted in the loop.
137+
// Windows adds \r\n for every line break but the Git-Stderr-Length variable,
138+
// counts it as only one character, throwing off the message length.
139+
var trimmedData = data.substring(0, fIndex).replace(/(\r\n)/gm, "\n");
140+
var fIndex = trimmedData.length
141+
142+
var messageLength = parseInt(footers["Git-Stderr-Length"]);
143+
var messageStartIndex = fIndex-messageLength;
144+
var message = trimmedData.substring(messageStartIndex, fIndex);
145+
146+
var output = trimmedData.substring(0, messageStartIndex);
147+
var rcode = parseInt(footers["Git-Return-Code"]);
148+
149+
if (rcode == 0) {
150+
if (callback) {
151+
callback(output);
152+
}
153+
// Return code is 0 but there is stderr output: this is a warning message
154+
if (message.length > 0) {
155+
if(warningCallback) {
156+
warningCallback(message);
157+
} else {
158+
webui.showWarning(message);
159+
}
160+
}
161+
} else {
162+
var displayMessage = ""
163+
if(output.length > 0){
164+
displayMessage += (output+"\n");
165+
}
166+
if(message.length > 0){
167+
displayMessage += message;
168+
}
169+
if(displayMessage.length > 0){
170+
// if(errorCallback) {
171+
// errorCallback(displayMessage);
172+
// } else{
173+
if(displayMessage.indexOf("self.document.Login") != -1){
174+
location.reload();
175+
return false;
176+
}
177+
webui.showError(displayMessage);
178+
//}
179+
} else {
180+
webui.showError("The command <pre>"+command.join(" ")+"</pre> failed because of an unknown reason. Returned response: \n\n"+data)
181+
}
182+
}
183+
},
184+
error: function(data) {
185+
var trimmedData = data.substring(0, fIndex).replace(/(\r\n)/gm, "\n");
186+
var fIndex = trimmedData.length
187+
188+
var messageLength = parseInt(footers["Git-Stderr-Length"]);
189+
var messageStartIndex = fIndex-messageLength;
190+
var message = trimmedData.substring(messageStartIndex, fIndex);
191+
webui.showError(message);
192+
},
193+
});
194+
}
195+
113196
webui.git = function(cmd, arg1, arg2, arg3, arg4) {
114197
// cmd = git command line arguments
115198
// other arguments = optional stdin content and a callback function.
@@ -2551,42 +2634,33 @@ webui.NewChangedFilesView = function(workspaceView) {
25512634

25522635
self.amend = function(message, details) {
25532636
var selectedFilesAsString = selectedItems.join(" ");
2554-
message = self.doubleQuotesToSingleQuotes(message);
2555-
details = self.doubleQuotesToSingleQuotes(details);
25562637

25572638
if (self.commitMsgEmpty()) {
2558-
webui.git("add " + selectedFilesAsString);
2559-
webui.git("commit --amend --no-edit -- " + selectedFilesAsString, function(output) {
2639+
webui.git_command(['add', selectedFilesAsString]);
2640+
webui.git_command(['commit', '--amend', '--no-edit', '--', selectedFilesAsString], function(output) {
25602641
webui.showSuccess(output);
25612642
workspaceView.update();
2562-
})
2643+
});
25632644
} else if (selectedItems.length != 0) {
2564-
webui.git("add " + selectedFilesAsString);
2565-
webui.git('commit --amend -m "' + message + '" -m "' + details + '" -- ' + selectedFilesAsString, function(output) {
2645+
webui.git_command(['add', selectedFilesAsString]);
2646+
webui.git_command(['commit', '--amend', '-m', message, '-m', 'details', '--', selectedFilesAsString], function(output) {
25662647
webui.showSuccess(output);
25672648
workspaceView.update();
2568-
})
2649+
});
25692650
} else {
2570-
webui.git('commit --amend --allow-empty -m "' + message + '" -m "' + details + '"', function(output) {
2651+
webui.git_command(['commit', '--amend', '--allow-empty', '-m', message, '-m', details], function(output) {
25712652
webui.showSuccess(output);
25722653
workspaceView.update();
2573-
})
2654+
});
25742655
}
25752656

25762657

25772658
}
25782659

2579-
self.doubleQuotesToSingleQuotes = function(string) {
2580-
return string.replace(/"/g, "'");
2581-
}
2582-
25832660
self.commit = function(message, details) {
25842661
var selectedFilesAsString = selectedItems.join(" ");
2585-
message = self.doubleQuotesToSingleQuotes(message);
2586-
details = self.doubleQuotesToSingleQuotes(details);
2587-
2588-
webui.git("add " + selectedFilesAsString);
2589-
webui.git('commit -m "' + message + '" -m "' + details + '" -- ' + selectedFilesAsString, function(output) {
2662+
webui.git_command(['add', selectedFilesAsString]);
2663+
webui.git_command(['commit', '-m', message, '-m', details, '--', selectedFilesAsString], function(output) {
25902664
webui.showSuccess(output);
25912665
workspaceView.update();
25922666
});

0 commit comments

Comments
 (0)