Skip to content

Commit 8c42f24

Browse files
committed
refactor: add node part of git extension into phoenix node core
1 parent 245eed7 commit 8c42f24

File tree

10 files changed

+469
-150
lines changed

10 files changed

+469
-150
lines changed

docs/API-Reference/command/Menus.md

Lines changed: 34 additions & 131 deletions
Large diffs are not rendered by default.

docs/API-Reference/utils/LocalizationUtils.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ const LocalizationUtils = brackets.getModule("utils/LocalizationUtils")
66
<a name="getLocalizedLabel"></a>
77

88
## getLocalizedLabel(locale) ⇒ <code>string</code>
9-
Converts a language code to its written name, if possible.
10-
If not possible, the language code is simply returned.
9+
Converts a language code to its written name, if possible.If not possible, the language code is simply returned.
1110

1211
**Kind**: global function
1312
**Returns**: <code>string</code> - The language's name or the given language code
@@ -44,15 +43,12 @@ Returns a relative time string (e.g., "2 days ago", "in 3 hours") based on the d
4443
| --- | --- | --- |
4544
| [date] | <code>Date</code> | The date to compare with the current date and time. If not given, defaults to now. |
4645
| [lang] | <code>string</code> | Optional language code to use for formatting (e.g., 'en', 'fr'). If not provided, defaults to the application locale or 'en'. |
47-
| [fromDate] | <code>string</code> | Optional date to use instead of now to compute the relative dateTime from. |
46+
| [fromDate] | <code>Date</code> | Optional date to use instead of now to compute the relative dateTime from. |
4847

4948
<a name="dateTimeFromNowFriendly"></a>
5049

5150
## dateTimeFromNowFriendly(date, [lang]) ⇒ <code>string</code>
52-
Returns an intelligent date string.
53-
- For dates within the last 30 days or the future: relative time (e.g., "2 days ago", "in 3 hours").
54-
- For dates earlier this year: formatted date (e.g., "Jan 5").
55-
- For dates not in the current year: formatted date with year (e.g., "Jan 5, 2023").
51+
Returns an intelligent date string.- For dates within the last 30 days or the future: relative time (e.g., "2 days ago", "in 3 hours").- For dates earlier this year: formatted date (e.g., "Jan 5").- For dates not in the current year: formatted date with year (e.g., "Jan 5, 2023").
5652

5753
**Kind**: global function
5854
**Returns**: <code>string</code> - - An intelligently formatted date string.

docs/API-Reference/widgets/PopUpManager.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,42 @@ Add Esc key handling for a popup DOM element.
2828
<a name="removePopUp"></a>
2929

3030
## removePopUp($popUp)
31-
Remove Esc key handling for a pop-up. Removes the pop-up from the DOM
32-
if the pop-up is currently visible and was not originally attached.
31+
Remove Esc key handling for a pop-up. Removes the pop-up from the DOMif the pop-up is currently visible and was not originally attached.
3332

3433
**Kind**: global function
3534

3635
| Param | Type |
3736
| --- | --- |
3837
| $popUp | <code>jQuery</code> |
3938

39+
<a name="_filterDropdown"></a>
40+
41+
## \_filterDropdown($popup, searchString)
42+
hides all elements in popup that doesn't match the given search string, also shows the search bar in popup
43+
44+
**Kind**: global function
45+
46+
| Param |
47+
| --- |
48+
| $popup |
49+
| searchString |
50+
51+
<a name="selectNextItem"></a>
52+
53+
## selectNextItem(direction, $popUp)
54+
Selects the next or previous item in the popup.
55+
56+
**Kind**: global function
57+
58+
| Param | Type | Description |
59+
| --- | --- | --- |
60+
| direction | <code>number</code> | +1 for next, -1 for prev |
61+
| $popUp | | |
62+
4063
<a name="listenToContextMenu"></a>
4164

4265
## listenToContextMenu(contextMenu)
43-
Context menus are also created in AppInit.htmlReady(), so they may not
44-
yet have been created when we get our AppInit.htmlReady() callback, so
45-
we provide this method to tell us when to start listening for their events
66+
Context menus are also created in AppInit.htmlReady(), so they may notyet have been created when we get our AppInit.htmlReady() callback, sowe provide this method to tell us when to start listening for their events
4667

4768
**Kind**: global function
4869

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-node/git/cli.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
const gitNodeConnector = global.createNodeConnector("phcode-git-core", exports);
2+
3+
const GIT_PROGRESS_EVENT = "git_progress";
4+
5+
let ChildProcess = require("child_process"),
6+
crossSpawn = require('cross-spawn'),
7+
ProcessUtils = require("./processUtils"),
8+
processMap = {},
9+
resolvedPaths = {};
10+
11+
function fixEOL(str) {
12+
if (str[str.length - 1] === "\n") {
13+
str = str.slice(0, -1);
14+
}
15+
return str;
16+
}
17+
18+
// handler with ChildProcess.exec
19+
// this won't handle cases where process outputs a large string
20+
function execute(directory, command, args, opts, callback) {
21+
// execute commands have to be escaped, spawn does this automatically and will fail if cmd is escaped
22+
if (command[0] !== "\"" || command[command.length - 1] !== "\"") {
23+
command = "\"" + command + "\"";
24+
}
25+
// http://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
26+
const toExec = command + " " + args.join(" ");
27+
processMap[opts.cliId] = ChildProcess.exec(toExec, {
28+
cwd: directory,
29+
maxBuffer: 20 * 1024 * 1024
30+
}, function (err, stdout, stderr) {
31+
delete processMap[opts.cliId];
32+
callback(err ? fixEOL(stderr) : undefined, err ? undefined : fixEOL(stdout));
33+
});
34+
}
35+
36+
// handler with cross-spawn
37+
function join(arr) {
38+
let result, index = 0, length;
39+
length = arr.reduce(function (l, b) {
40+
return l + b.length;
41+
}, 0);
42+
result = new Buffer(length);
43+
arr.forEach(function (b) {
44+
b.copy(result, index);
45+
index += b.length;
46+
});
47+
return fixEOL(result.toString("utf8"));
48+
}
49+
50+
function spawn(directory, command, args, opts, callback) {
51+
// https://github.com/creationix/node-git
52+
const child = crossSpawn(command, args, {
53+
cwd: directory
54+
});
55+
child.on("error", function (err) {
56+
callback(err.stack, undefined);
57+
});
58+
59+
processMap[opts.cliId] = child;
60+
61+
let exitCode, stdout = [], stderr = [];
62+
child.stdout.addListener("data", function (text) {
63+
stdout[stdout.length] = text;
64+
});
65+
child.stderr.addListener("data", function (text) {
66+
// Git writes its informational messages (such as Successfully rebased
67+
// and updated) to stderr. This behavior is intentional because Git uses
68+
// stderr for all output that is not a direct result of the command (e.g.,
69+
// status updates, progress, or errors).
70+
if (opts.watchProgress) {
71+
gitNodeConnector.triggerPeer(GIT_PROGRESS_EVENT, {
72+
cliId: opts.cliId,
73+
time: (new Date()).getTime(),
74+
data: fixEOL(text.toString("utf8"))
75+
});
76+
}
77+
stderr[stderr.length] = text;
78+
});
79+
child.addListener("exit", function (code) {
80+
exitCode = code;
81+
});
82+
child.addListener("close", function () {
83+
delete processMap[opts.cliId];
84+
callback(exitCode > 0 ? join(stderr) : undefined,
85+
exitCode > 0 ? undefined : join(stdout));
86+
});
87+
child.stdin.end();
88+
}
89+
90+
function doIfExists(method, directory, command, args, opts, callback) {
91+
// do not call executableExists if we already know it exists
92+
if (resolvedPaths[command]) {
93+
return method(directory, resolvedPaths[command], args, opts, callback);
94+
}
95+
96+
ProcessUtils.executableExists(command, function (err, exists, resolvedPath) {
97+
if (exists) {
98+
resolvedPaths[command] = resolvedPath;
99+
return method(directory, resolvedPath, args, opts, callback);
100+
} else {
101+
callback("ProcessUtils can't resolve the path requested: " + command);
102+
}
103+
});
104+
}
105+
106+
function executeIfExists({directory, command, args, opts}) {
107+
return new Promise(function (resolve, reject) {
108+
doIfExists(execute, directory, command, args, opts, (err, stdout)=>{
109+
if(err){
110+
reject(err);
111+
} else {
112+
resolve(stdout);
113+
}
114+
});
115+
});
116+
}
117+
118+
function spawnIfExists({directory, command, args, opts}) {
119+
return new Promise(function (resolve, reject) {
120+
doIfExists(spawn, directory, command, args, opts, (err, stdout)=>{
121+
if(err){
122+
reject(err);
123+
} else {
124+
resolve(stdout);
125+
}
126+
});
127+
});
128+
}
129+
130+
function kill(cliId) {
131+
return new Promise(function (resolve, reject) {
132+
const process = processMap[cliId];
133+
if (!process) {
134+
reject("Couldn't find process to kill with ID:" + cliId);
135+
}
136+
delete processMap[cliId];
137+
resolve(""); // at this point we resolve anyways as we cant do anything after deleting the object
138+
ProcessUtils.getChildrenOfPid(process.pid, function (err, children) {
139+
// kill also parent process
140+
children.push(process.pid);
141+
children.forEach(function (pid) {
142+
ProcessUtils.killSingleProcess(pid);
143+
});
144+
});
145+
});
146+
}
147+
148+
function which({command}) {
149+
return new Promise(function (resolve, reject) {
150+
ProcessUtils.executableExists(command, function (err, exists, resolvedPath) {
151+
if (exists) {
152+
resolve(resolvedPath);
153+
} else {
154+
reject("ProcessUtils can't resolve the path requested: " + command);
155+
}
156+
});
157+
});
158+
}
159+
160+
exports.execute = executeIfExists;
161+
exports.spawn = spawnIfExists;
162+
exports.kill = kill;
163+
exports.which = which;

src-node/git/processUtils-test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const ProcessUtils = require("./processUtils");
2+
3+
/*
4+
var pid = 5064;
5+
ProcessUtils.getChildrenOfPid(pid, function (err, children) {
6+
console.log(children);
7+
children.push(pid);
8+
children.forEach(function (pid) {
9+
ProcessUtils.killSingleProcess(pid);
10+
});
11+
});
12+
*/
13+
14+
[
15+
"git",
16+
"C:\\Program Files (x86)\\Git\\cmd\\git.exe",
17+
"C:/Program Files (x86)/Git/cmd/git.exe",
18+
"C:/Program Files (x86)/Git/cmd/git2.exe",
19+
"C:/Program Files (x86)/Git/cmd/",
20+
"C:/Program Files (x86)/Git/cmd",
21+
"C:\\Program Files (x86)\\Git\\Git Bash.vbs"
22+
].forEach(function (path) {
23+
24+
ProcessUtils.executableExists(path, function (err, exists, resolvedPath) {
25+
console.log("ProcessUtils.executableExists for: " + path);
26+
console.log(" - exists: " + exists);
27+
console.log(" - resolvedPath: " + resolvedPath);
28+
});
29+
30+
});
31+
32+
/*
33+
ProcessUtils.executableExists("git", function (err, result, resolvedPath) {
34+
console.log("git");
35+
console.log(result);
36+
});
37+
ProcessUtils.executableExists("C:\\Program Files (x86)\\Git\\cmd\\git.exe", function (err, result) {
38+
console.log("result for C:\\Program Files (x86)\\Git\\cmd\\git.exe");
39+
console.log(result);
40+
});
41+
ProcessUtils.executableExists("C:/Program Files (x86)/Git/cmd/git.exe", function (err, result) {
42+
console.log("result for C:/Program Files (x86)/Git/cmd/git.exe");
43+
console.log(result);
44+
});
45+
46+
ProcessUtils.executableExists("C:/Program Files (x86)/Git/cmd/git2.exe", function (err, result) {
47+
console.log("result for C:/Program Files (x86)/Git/cmd/git2.exe");
48+
console.log(result);
49+
});
50+
ProcessUtils.executableExists("C:/Program Files (x86)/Git/cmd/", function (err, result) {
51+
console.log("result for C:/Program Files (x86)/Git/cmd/");
52+
console.log(result);
53+
});
54+
ProcessUtils.executableExists("C:/Program Files (x86)/Git/cmd", function (err, result) {
55+
console.log("result for C:/Program Files (x86)/Git/cmd");
56+
console.log(result);
57+
});
58+
*/

0 commit comments

Comments
 (0)