forked from droundy/fac
-
Notifications
You must be signed in to change notification settings - Fork 0
/
git.c
292 lines (262 loc) · 7.77 KB
/
git.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#define _XOPEN_SOURCE 700
#include "fac.h"
#include "errors.h"
#include <assert.h>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#include <direct.h> // for _getcwd
#define getcwd _getcwd
#include <process.h> // for spawnvp
int ReadChildProcess(char **output, char *cmdline) {
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES sa;
printf("\n->Start of parent execution.\n");
// Set the bInheritHandle flag so pipe handles are inherited.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0) ) {
exit(1);
}
// Ensure the read handle to the pipe for STDOUT is not inherited
if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ){
exit(1);
}
// Create a child process that uses the previously created pipe
// for STDOUT.
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
bool bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
// Set up members of the STARTUPINFO structure.
// This structure specifies the STDOUT handle for redirection.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
//siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(NULL,
cmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
CloseHandle(g_hChildStd_OUT_Wr);
// If an error occurs, exit the application.
if ( ! bSuccess ) {
exit(1);
}
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
DWORD dwRead = 0;
int bufsize = 1024;
*output = malloc(bufsize);
int read_offset = 0;
do {
bSuccess=ReadFile( g_hChildStd_OUT_Rd, *output + read_offset,
bufsize-read_offset-1, &dwRead, NULL);
read_offset += dwRead; // advance pointer to read location for next read
(*output)[read_offset] = 0; // null-terminate output
if (bufsize - read_offset < 6) {
bufsize *= 2;
*output = realloc(*output, bufsize);
}
} while (bSuccess && dwRead);
// To avoid resource leaks close handle explicitly.
CloseHandle(g_hChildStd_OUT_Rd);
// Wait until child process exits.
WaitForSingleObject( piProcInfo.hProcess, INFINITE );
int result = -1;
if(!GetExitCodeProcess(piProcInfo.hProcess,(LPDWORD)&result)) {
int myerrno = GetLastError();
error(1, myerrno, "GetExitCodeProcess() failed");
}
return result;
}
#else
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#endif
char *go_to_git_top() {
char *buf = git_revparse("--show-toplevel");
if (chdir(buf) != 0) {
printf("Error changing to git toplevel directory!\n");
exit(1);
}
return buf;
}
char *git_revparse(const char *flag) {
#ifdef _WIN32
char *buf = 0;
char *cmdline = malloc(500);
if (snprintf(cmdline, 500, "git rev-parse %s", flag) >= 500) {
printf("bug: long argument to git_revparse: %s\n", flag);
return 0;
}
int retval = ReadChildProcess(&buf, cmdline);
free(cmdline);
if (retval) {
free(buf);
return 0;
}
int stdoutlen = strlen(buf);
#else
const char *templ = "/tmp/fac-XXXXXX";
char *namebuf = malloc(strlen(templ)+1);
strcpy(namebuf, templ);
int out = mkstemp(namebuf);
unlink(namebuf);
free(namebuf);
pid_t new_pid = fork();
if (new_pid == 0) {
char **args = malloc(4*sizeof(char *));
close(1);
if (dup(out) != 1) error(1, errno, "trouble duping stdout for ");
close(2);
open("/dev/null", O_WRONLY);
args[0] = "git";
args[1] = "rev-parse";
args[2] = (char *)flag;
args[3] = 0;
execvp("git", args);
exit(0);
}
int status = 0;
if (waitpid(new_pid, &status, 0) != new_pid) {
printf("Unable to exec git ls-files\n");
return 0; // fixme should exit
}
if (WEXITSTATUS(status)) {
printf("Unable to run git rev-parse successfully %d\n", WEXITSTATUS(status));
return 0;
}
off_t stdoutlen = lseek(out, 0, SEEK_END);
lseek(out, 0, SEEK_SET);
char *buf = malloc(stdoutlen);
if (read(out, buf, stdoutlen) != stdoutlen) {
printf("Error reading output of git rev-parse %s\n", flag);
free(buf);
return 0;
}
#endif
for (int i=0;i<stdoutlen;i++) {
if (buf[i] == '\n') {
buf[i] = 0;
}
}
return buf;
}
void add_git_files(struct all_targets *all) {
#ifdef _WIN32
char *buf = 0;
int retval = ReadChildProcess(&buf, "git ls-files");
if (retval) {
free(buf);
return;
}
int stdoutlen = strlen(buf);
#else
const char *templ = "/tmp/fac-XXXXXX";
char *namebuf = malloc(strlen(templ)+1);
strcpy(namebuf, templ);
int out = mkstemp(namebuf);
unlink(namebuf);
free(namebuf);
pid_t new_pid = fork();
if (new_pid == 0) {
char **args = malloc(3*sizeof(char *));
close(1);
if (dup(out) != 1) error(1, errno, "trouble duping stdout for git ls-files");
close(2);
open("/dev/null", O_WRONLY);
args[0] = "git";
args[1] = "ls-files";
args[2] = 0;
execvp("git", args);
exit(0);
}
int status = 0;
if (waitpid(new_pid, &status, 0) != new_pid) {
printf("Unable to exec git ls-files\n");
return; // fixme should exit
}
if (WEXITSTATUS(status)) {
printf("Unable to run git ls-files successfully %d\n", WEXITSTATUS(status));
// return 0;
}
off_t stdoutlen = lseek(out, 0, SEEK_END);
lseek(out, 0, SEEK_SET);
char *buf = malloc(stdoutlen);
if (read(out, buf, stdoutlen) != stdoutlen) {
printf("Error reading output of git ls-files\n");
free(buf);
return; // fixme should exit
}
#endif
int last_start = 0;
for (int i=0;i<stdoutlen;i++) {
if (buf[i] == '\n') {
buf[i] = 0;
char *path = absolute_path(root, buf + last_start);
struct target *t = create_target(all, path);
free(path);
assert(t);
t->is_in_git = true;
// Now check if this file is in a subdirectory...
for (int j=i-1;j>last_start;j--) {
if (buf[j] == '/') {
buf[j] = 0;
char *path = absolute_path(root, buf + last_start);
struct target *t = create_target(all, path);
free(path);
assert(t);
t->is_in_git = true;
}
}
last_start = i+1;
}
}
free(buf);
}
void git_add(const char *path) {
const char **args = malloc(5*sizeof(char *));
args[0] = "git";
args[1] = "add";
args[2] = "--";
args[3] = path;
args[4] = 0;
#ifdef _WIN32
int retval = spawnvp(P_WAIT, "git", (char **)args);
#else
pid_t new_pid = fork();
if (new_pid == 0) {
close(0);
execvp("git", (char **)args);
error(1, errno, "running git");
}
int status = 0;
if (waitpid(new_pid, &status, 0) != new_pid) {
printf("Unable to exec git add -- %s\n", path);
return; // fixme should exit
}
int retval = WEXITSTATUS(status);
#endif
if (retval) {
printf("Unable to run git add -- %s successfully %d\n", path, retval);
}
}