1 /*
2 * Copyright 2009, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include <map>
27 #include <string>
28 #include <vector>
29 #include <cstdio>
30 #include <stdlib.h>
31 #include <string.h>
32
33 using namespace std;
34
35 string WEBKITLIB = "external/webkit";
36
37 string oldBaseStr;
38 string oldCmdStr;
39 string newBaseStr;
40 string newCmdStr;
41 string sandboxBaseStr;
42 string sandboxCmdStr;
43 string outputDir;
44 string scratchDir;
45
46 const char* oldBase;
47 const char* oldCmd;
48 const char* newBase;
49 const char* newCmd;
50 const char* sandboxBase;
51 const char* sandboxCmd;
52
53 bool assert_debug;
54
55 #define myassert(a) do { \
56 if (!(a)) { \
57 fprintf(stderr, "%s %d %s\n", __FUNCTION__, __LINE__, #a); \
58 fflush(stderr); \
59 if (assert_debug) for(;;); else exit(0); \
60 } \
61 } while(false)
62
63 class Options {
64 public:
Options()65 Options() : emitGitCommands(false), emitPerforceCommands(false),
66 mergeMake(true), copyOther(true), mergeCore(true),
67 removeEmptyDirs(true), removeSVNDirs(true), debug(false),
68 execute(false), verbose(false), cleared(false)
69 {
70 }
71
72 bool finish();
clearOnce()73 void clearOnce()
74 {
75 if (cleared)
76 return;
77 mergeMake = copyOther = mergeCore = removeEmptyDirs = removeSVNDirs = false;
78 cleared = true;
79 }
80 string androidWebKit;
81 string baseWebKit;
82 string newWebKit;
83 bool emitGitCommands;
84 bool emitPerforceCommands;
85 bool mergeMake;
86 bool copyOther;
87 bool mergeCore;
88 bool removeEmptyDirs;
89 bool removeSVNDirs;
90 bool debug;
91 bool execute;
92 bool verbose;
93 private:
94 bool cleared;
95 };
96
97 Options options;
98
GetFile(string fileNameStr,size_t * sizePtr=NULL,int * lines=NULL)99 char* GetFile(string fileNameStr, size_t* sizePtr = NULL, int* lines = NULL)
100 {
101 const char* fileName = fileNameStr.c_str();
102 FILE* file = fopen(fileName, "r");
103 if (file == NULL)
104 {
105 fprintf(stderr, "can't read %s\n", fileName);
106 myassert(0);
107 return 0;
108 }
109 fseek(file, 0, SEEK_END);
110 size_t size = ftell(file);
111 if (sizePtr)
112 *sizePtr = size;
113 fseek(file, 0, SEEK_SET);
114 char* buffer = new char[size + 2];
115 fread(buffer, size, 1, file);
116 buffer[size] = buffer[size + 1] = '\0';
117 int lineCount = 0;
118 for (size_t index = 0; index < size; index++) {
119 if (buffer[index] == '\n') {
120 buffer[index] = '\0';
121 lineCount++;
122 }
123 }
124 if (lines)
125 *lines = lineCount;
126 fclose(file);
127 return buffer;
128 }
129
finish()130 bool Options::finish()
131 {
132 ::assert_debug = options.debug;
133 if (androidWebKit.size() == 0) {
134 fprintf(stderr, "missing --android parameter");
135 return false;
136 }
137 if (baseWebKit.size() == 0) {
138 fprintf(stderr, "missing --basewebkit parameter");
139 return false;
140 }
141 if (newWebKit.size() == 0) {
142 fprintf(stderr, "missing --newwebkit parameter");
143 return false;
144 }
145 sandboxBaseStr = androidWebKit + "/" + WEBKITLIB;
146 sandboxCmdStr = sandboxBaseStr;
147 int err = system("pwd > pwd.txt");
148 myassert(err != -1);
149 outputDir = string(GetFile("pwd.txt"));
150 system("rm pwd.txt");
151 myassert(outputDir.size() > 0);
152 scratchDir = outputDir;
153 outputDir += "/scripts/";
154 string outputMkdir = "test -d " + outputDir + " || mkdir " + outputDir;
155 system(outputMkdir.c_str());
156 scratchDir += "/scratch/";
157 string scratchMkdir = "test -d " + scratchDir + " || mkdir " + scratchDir;
158 system(scratchMkdir.c_str());
159 oldBaseStr = baseWebKit;
160 oldCmdStr = oldBaseStr;
161 newBaseStr = newWebKit;
162 newCmdStr = newBaseStr;
163 oldBase = oldBaseStr.c_str();
164 oldCmd = oldCmdStr.c_str();
165 newBase = newBaseStr.c_str();
166 newCmd = newCmdStr.c_str();
167 sandboxBase = sandboxBaseStr.c_str();
168 sandboxCmd = sandboxCmdStr.c_str();
169 return true;
170 }
171
172 // scratch files
ScratchFile(const char * name)173 string ScratchFile(const char* name)
174 {
175 return scratchDir + name + ".txt";
176 }
177
178 FILE* commandFile;
179 FILE* copyDirFile;
180 FILE* oopsFile;
181
SedEscape(const char * str)182 string SedEscape(const char* str)
183 {
184 string result;
185 char ch;
186 while ((ch = *str++) != '\0') {
187 if (ch == '/' || ch == '\\' || ch == '$')
188 result += '\\';
189 result += ch;
190 }
191 return result;
192 }
193
List(const char * base,char * name,const char * workingDir)194 char* List(const char* base, char* name, const char* workingDir)
195 {
196 string listStr = "ls -F \"";
197 listStr += string(base) + "/" + workingDir + "\" > " + ScratchFile(name);
198 int err = system(listStr.c_str());
199 myassert(err == 0);
200 return GetFile(ScratchFile(name));
201 }
202
Merge(const char * oldDir,const char * oldFile,const char * newDir,const char * newFile,const char * outFile)203 bool Merge(const char* oldDir, const char* oldFile, const char* newDir, const char* newFile,
204 const char* outFile)
205 {
206 char scratch[2048];
207
208 sprintf(scratch, "merge -p -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\" > %s",
209 sandboxBase, oldDir, oldFile, oldBase, oldDir, oldFile, newBase, newDir, newFile, outFile);
210 int err = system(scratch);
211 myassert(err == 0 || err ==1 || err == 256);
212 return err == 0;
213 }
214
Merge(const char * dir,const char * file)215 bool Merge(const char* dir, const char* file)
216 {
217 return Merge(dir, file, dir, file, "/dev/null");
218 }
219
220 /*
221 static const char* skipNonSpace(char** linePtr) {
222 char* line = *linePtr;
223 while (line[0] && isspace(line[0]) == false)
224 line++;
225 *linePtr = line;
226 return line;
227 }
228 */
229
endsWith(const char * str,const char * end)230 static bool endsWith(const char* str, const char* end) {
231 size_t endLen = strlen(end);
232 const char* endStr = str + strlen(str) - endLen;
233 return endStr >= str && strcmp(endStr, end) == 0;
234 }
235
skipSpace(char ** linePtr)236 static void skipSpace(char** linePtr) {
237 char* line = *linePtr;
238 while (isspace(line[0]))
239 line++;
240 *linePtr = line;
241 }
242
243 /*
244 static void setTrimmed(string& str, char* loc, int len) {
245 char* start = loc;
246 skipSpace(&loc);
247 len -= loc - start;
248 while (len > 0 && isspace(loc[len - 1]))
249 len--;
250 str = string(loc, len);
251 }
252 */
253
skipText(char ** linePtr,const char * text)254 static bool skipText(char** linePtr, const char* text) {
255 skipSpace(linePtr);
256 size_t length = strlen(text);
257 bool result = strncmp(*linePtr, text, length) == 0;
258 if (result)
259 *linePtr += length;
260 skipSpace(linePtr);
261 return result;
262 }
263
isTokenChar(char ch)264 static bool isTokenChar(char ch) {
265 return isalnum(ch) || ch == '_';
266 }
267
268 struct Pair {
269 char* name;
270 int brace;
271 };
272
273 class Parse {
274 public:
275 char* m_text;
276 bool m_inComment;
277 bool m_inFunction;
278 bool m_inFindFunctionType;
279 vector<Pair> m_classes;
280 vector<Pair> m_namespaces;
281 vector<Pair> m_preprocessorConditions;
282 string m_functionName;
283 string m_functionDeclaration;
284 string m_classDeclaration;
285 int m_braceLevel;
286 int m_functionBrace;
287
Parse(char * text)288 Parse(char* text) : m_text(text), m_inComment(false), m_inFunction(false), m_inFindFunctionType(false),
289 m_braceLevel(0), m_functionBrace(0) {}
290
CheckForBrace()291 int CheckForBrace()
292 {
293 int indent = 0;
294 // don't count braces in strings, chars, comments
295 do {
296 char* openBrace = strchr(m_text, '{');
297 char* closeBrace = strchr(m_text, '}');
298 if (openBrace == NULL && closeBrace == NULL)
299 break;
300 char* brace = openBrace == NULL ? closeBrace : closeBrace == NULL ? openBrace :
301 openBrace < closeBrace ? openBrace : closeBrace;
302 char* doubleQ = strchr(m_text, '"');
303 char* singleQ = strchr(m_text, '\'');
304 char* quote = doubleQ == NULL ? singleQ : singleQ == NULL ? doubleQ :
305 doubleQ < singleQ ? doubleQ : singleQ;
306 char quoteMark = quote == doubleQ ? '"' : '\'';
307 if (quote && quote < brace) {
308 myassert(quote[-1] != '\\');
309 do {
310 quote = strchr(quote + 1, quoteMark);
311 myassert(doubleQ);
312 } while (quote[-1] == '\\');
313 m_text = quote + 1;
314 continue;
315 }
316 indent += openBrace != NULL ? 1 : -1;
317 m_text = openBrace + 1;
318 } while (m_text[0] != '\0');
319 return indent;
320 }
321
ParseLine()322 int ParseLine()
323 {
324 size_t textLen = strlen(m_text);
325 char* lineStart = m_text;
326 char* commentStart;
327 if (m_text[0] == '\0')
328 goto nextLine;
329 if (m_inComment == false && m_text[0] == '/') {
330 m_inComment = m_text[1] == '*';
331 if (m_text[1] == '/' || m_text[1] == '*')
332 goto nextLine;
333 }
334 commentStart = m_text; // before anything else, turn embedded comments into their own lines
335 if (m_inComment == false && skipText(&commentStart, "//")) {
336 if (commentStart < lineStart + textLen)
337 commentStart[0] = '/';
338 else
339 commentStart[-1] = ' ';
340 commentStart -= 2;
341 commentStart[0] = '\0';
342 textLen = commentStart - lineStart;
343 goto nextLine;
344 }
345 if (m_inComment || skipText(&commentStart, "/*")) {
346 char* commentEnd = commentStart;
347 if (skipText(&commentEnd, "*/")) {
348 if (commentEnd < lineStart + textLen) {
349 commentEnd[-1] = '\0';
350 textLen = commentEnd - lineStart - 2;
351 }
352 if (m_inComment) {
353 m_inComment = false;
354 goto nextLine;
355 }
356 }
357 if (m_inComment)
358 goto nextLine;
359 memcpy(commentStart - 2, "\0/*", 3);
360 textLen = commentStart - lineStart - 2;
361 }
362 if (skipText(&m_text, "#include"))
363 goto nextLine;
364 if (skipText(&m_text, "#if") || skipText(&m_text, "#else")) {
365 Pair condition = { lineStart, m_braceLevel };
366 m_preprocessorConditions.push_back(condition);
367 goto nextLine;
368 }
369 {
370 bool is_endif = false;
371 if (skipText(&m_text, "#elif") || (is_endif = skipText(&m_text, "#endif")) != false) { // pop prior elif, if
372 char* lastText;
373 do {
374 int last = m_preprocessorConditions.size() - 1;
375 myassert(last >= 0);
376 lastText = m_preprocessorConditions[last].name;
377 m_preprocessorConditions.pop_back();
378 } while (is_endif && skipText(&lastText, "#else") == true);
379 goto nextLine;
380 }
381 }
382 if (skipText(&m_text, "namespace")) {
383 Pair space = { lineStart, m_braceLevel };
384 m_namespaces.push_back(space);
385 goto checkForBrace;
386 }
387 if (m_inFunction)
388 goto checkForBrace;
389 // detect functions by looking for token preceding open-paren.
390 if (m_inFindFunctionType == false) {
391 char* openParen = strchr(m_text, '(');
392 if (openParen) {
393 char* last = openParen;
394 while (last > m_text && isspace(last[-1]))
395 --last;
396 while (last > m_text && ((isTokenChar(last[-1]) || last[-1] == ':') && last[-2] == ':'))
397 --last;
398 myassert(isdigit(last[0]) == false);
399 if (isTokenChar(last[0])) {
400 m_inFindFunctionType = true;
401 m_functionName = string(last);
402 }
403 }
404 }
405 {
406 char* openBrace = strchr(m_text, '{');
407 char* semiColon = strchr(m_text, ';');
408 if (semiColon != NULL && semiColon < openBrace)
409 openBrace = NULL;
410 // functions are of the form: type (class::)*function(parameter-list) {
411 // all of which may be on separate lines
412 // so keep track of returntype, class, function, paramlist, openbrace separately
413 if (m_inFindFunctionType == true) { // look ahead to see which comes first, a semicolon or an open brace
414 if (openBrace) {
415 m_functionBrace = ++m_braceLevel;
416 m_inFunction = true;
417 m_inFindFunctionType = false;
418 m_text = openBrace + 1;
419 goto checkForBrace;
420 }
421 if (semiColon != NULL) { // a function declaration
422 m_inFindFunctionType = false;
423 m_functionDeclaration = m_functionName;
424 m_functionName.erase(0, m_functionName.length());
425 } else
426 goto nextLine;
427 }
428 // FIXME what if class line has neither brace nor semi?
429 if (skipText(&m_text, "class")) {
430 if (openBrace > m_text) {
431 Pair _class = { lineStart, m_braceLevel };
432 m_classes.push_back(_class);
433 } else if (semiColon != NULL) {
434 m_classDeclaration = lineStart; // !!! FIXME should have function form as above
435 }
436 }
437 }
438 checkForBrace:
439 m_braceLevel += CheckForBrace();
440 if (m_functionBrace > 0 && m_braceLevel <= m_functionBrace) {
441 m_functionName.erase(0, m_functionName.length());
442 m_functionBrace = 0;
443 }
444 nextLine:
445 return textLen;
446 }
447
448 };
449
GetAndroidDiffs(const char * dir,const char * filename)450 char* const GetAndroidDiffs(const char* dir, const char* filename)
451 {
452 char scratch[2048];
453 string diffsFile = ScratchFile(__FUNCTION__);
454 sprintf(scratch, "diff \"%s/%s/%s\" \"%s/%s/%s\" > %s", sandboxBase, dir,
455 filename, oldBase, dir, filename, diffsFile.c_str());
456 int err = system(scratch);
457 myassert(err == 0 || err == 256);
458 char* const diffs = GetFile(diffsFile);
459 return diffs;
460 }
461
CheckForExec(const char * base1,const char * dir1,const char * file1,const char * base2,const char * dir2,const char * file2,bool * ex1,bool * ex2)462 void CheckForExec(const char* base1, const char* dir1, const char* file1,
463 const char* base2, const char* dir2, const char* file2, bool* ex1, bool* ex2)
464 {
465 size_t file1Len = strlen(file1);
466 size_t file2Len = strlen(file2);
467 bool file1Ex = file1[file1Len - 1] == '*';
468 bool file2Ex = file2[file2Len - 1] == '*';
469 if (file1Ex != file2Ex) {
470 fprintf(stderr, "warning: %s/%s/%s has %sexec bit set while"
471 " %s/%s/%s has %sexec bit set\n",
472 base1, dir1, file1, file1Ex ? "" : "no ",
473 base2, dir2, file2, file2Ex ? "" : "no ");
474 }
475 if (ex1) *ex1 = file1Ex;
476 if (ex2) *ex2 = file2Ex;
477 }
478
CompareFiles(const char * base1,const char * dir1,const char * file1,const char * base2,const char * dir2,const char * file2)479 bool CompareFiles(const char* base1, const char* dir1, const char* file1,
480 const char* base2, const char* dir2, const char* file2)
481 {
482 char scratch[2048];
483 bool file1Ex, file2Ex;
484 string compareFileStr = ScratchFile(__FUNCTION__);
485 CheckForExec(base1, dir1, file1, base2, dir2, file2, &file1Ex, &file2Ex);
486 sprintf(scratch, "diff --brief \"%s/%s/%.*s\" \"%s/%s/%.*s\" > %s",
487 base1, dir1, (int) strlen(file1) - (int) file1Ex, file1,
488 base2, dir2, (int) strlen(file2) - (int) file2Ex, file2,
489 compareFileStr.c_str());
490 int err = system(scratch);
491 myassert(err == 0 || err == 256);
492 char* scratchText = GetFile(compareFileStr);
493 size_t len = strlen(scratchText);
494 delete[] scratchText;
495 return len > 0;
496 }
497
CompareFiles(const char * base1,const char * base2,const char * dir,const char * file)498 bool CompareFiles(const char* base1, const char* base2, const char* dir, const char* file)
499 {
500 return CompareFiles(base1, dir, file, base2, dir, file);
501 }
502
Compare(char * one,size_t len1,char * two,size_t len2)503 int Compare(char* one, size_t len1, char* two, size_t len2)
504 {
505 char* o_end = one + len1;
506 char* t_end = two + len2;
507 do {
508 if (one == o_end)
509 return two == t_end ? 0 : 1;
510 if (two == t_end)
511 return -1;
512 char o = *one++;
513 char t = *two++;
514 if (o == t)
515 continue;
516 if (o == '/')
517 return -1;
518 if (t == '/')
519 return 1;
520 return o < t ? -1 : 1;
521 } while (true);
522 myassert(0);
523 return 0;
524 }
525
Find(const char * oldList)526 string Find(const char* oldList)
527 {
528 string result;
529 char scratch[2048];
530 // look in WebCore and JavaScriptCore
531 string findWebCore = ScratchFile("FindWebCore");
532 sprintf(scratch, "cd %s%s ; find . -name \"%s\" > %s",
533 newBase, "/WebCore", oldList, findWebCore.c_str());
534 int err = system(scratch);
535 myassert(err == 0 || err == 256);
536 int webCount;
537 char* foundInWebCore = GetFile(findWebCore, NULL, &webCount);
538 char* originalFoundInWebCore = foundInWebCore;
539 string findJavaScriptCore = ScratchFile("FindJavaScriptCore");
540 sprintf(scratch, "cd %s%s ; find . -name \"%s\" > %s",
541 newBase, "/JavaScriptCore", oldList, findJavaScriptCore.c_str());
542 err = system(scratch);
543 myassert(err == 0 || err == 256);
544 int javaScriptCount;
545 char* foundInJavaScriptCore = GetFile(findJavaScriptCore, NULL, &javaScriptCount);
546 char* originalFoundInJavaScriptCore = foundInJavaScriptCore;
547 if (webCount == 1 && javaScriptCount == 0) {
548 result = "WebCore/" + string(&foundInWebCore[2]);
549 } else if (webCount == 0 && javaScriptCount == 1) {
550 result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
551 } else if (webCount == 1 && javaScriptCount == 1 &&
552 strncmp(&foundInWebCore[2], "ForwardingHeaders/", 18) == 0) {
553 result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
554 } else if (webCount == 1 && javaScriptCount == 1 &&
555 strncmp(&foundInJavaScriptCore[2], "API/tests/", 10) == 0) {
556 result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
557 } else if (webCount + javaScriptCount > 0) {
558 fprintf(stderr, "deleted file \"%s\" has more than one possible rename:\n", oldList);
559 int index;
560 for (index = 0; index < webCount; index++) {
561 fprintf(stderr, "WebCore/%s\n", &foundInWebCore[2]);
562 foundInWebCore += strlen(foundInWebCore) + 1;
563 }
564 for (index = 0; index < javaScriptCount; index++) {
565 fprintf(stderr, "JavaScriptCore/%s\n", &foundInJavaScriptCore[2]);
566 foundInJavaScriptCore += strlen(foundInJavaScriptCore) + 1;
567 }
568 }
569 delete[] originalFoundInWebCore;
570 delete[] originalFoundInJavaScriptCore;
571 return result;
572 }
573
GetMakeAndExceptions(const char * dir,const char * filename,size_t * makeSize,string * excludedFilesPtr,string * excludedGeneratedPtr,string * excludedDirsPtr,string * androidFilesPtr,char ** startPtr,char ** localStartPtr)574 char* GetMakeAndExceptions(const char* dir, const char* filename, size_t* makeSize,
575 string* excludedFilesPtr, string* excludedGeneratedPtr,
576 string* excludedDirsPtr, string* androidFilesPtr,
577 char** startPtr, char** localStartPtr)
578 {
579 char scratch[1024];
580 sprintf(scratch, "%s/%s/%s", sandboxBase, dir, filename);
581 char* makeFile = GetFile(scratch, makeSize);
582 char* start = makeFile;
583 do { // find first filename in makefile
584 if (strncmp(start, "# LOCAL_SRC_FILES_EXCLUDED := \\", 30) == 0)
585 break;
586 start += strlen(start) + 1;
587 } while (start < makeFile + *makeSize);
588 myassert(start[0] != '\0');
589 start += strlen(start) + 1;
590 // construct one very large regular expression that looks like:
591 // echo '%s' | grep -v -E 'DerivedSources.cpp|WebCorePrefix.cpp...'
592 // to filter out matches that aren't allowed
593 // wildcards '*' in the original need to be expanded to '.*'
594 string excludedFiles = "grep -v -E '";
595 while (strncmp(start, "#\t", 2) == 0) {
596 start += 2;
597 char ch;
598 while ((ch = *start++) != ' ') {
599 if (ch == '*')
600 excludedFiles += '.';
601 else if (ch == '.')
602 excludedFiles += '\\';
603 excludedFiles += ch;
604 }
605 excludedFiles += "|";
606 myassert(*start == '\\');
607 start += 2;
608 }
609 excludedFiles[excludedFiles.size() - 1] = '\'';
610 *excludedFilesPtr = excludedFiles;
611 do {
612 if (strncmp(start, "# LOCAL_GENERATED_FILES_EXCLUDED := \\", 37) == 0 ||
613 strncmp(start, "# LOCAL_DIR_WILDCARD_EXCLUDED := \\", 34) == 0)
614 break;
615 start += strlen(start) + 1;
616 } while (start < makeFile + *makeSize);
617 if (strncmp(start, "# LOCAL_GENERATED_FILES_EXCLUDED := \\", 37) == 0) {
618 string excludedGenerated = "grep -v -E '";
619 start += strlen(start) + 1;
620 while (strncmp(start, "#\t", 2) == 0) {
621 start += 2;
622 char ch;
623 while ((ch = *start++) != ' ') {
624 if (ch == '*')
625 excludedGenerated += '.';
626 else if (ch == '.')
627 excludedGenerated += '\\';
628 excludedGenerated += ch;
629 }
630 excludedGenerated += "|";
631 myassert(*start == '\\');
632 start += 2;
633 }
634 myassert(excludedGeneratedPtr);
635 excludedGenerated[excludedGenerated.size() - 1] = '\'';
636 *excludedGeneratedPtr = excludedGenerated;
637 }
638 do { // find first filename in makefile
639 if (strncmp(start, "# LOCAL_DIR_WILDCARD_EXCLUDED := \\", 34) == 0)
640 break;
641 start += strlen(start) + 1;
642 } while (start < makeFile + *makeSize);
643 if (start[0] != '\0') {
644 string excludedDirs = "-e '/\\.vcproj\\// d' -e '/\\.svn\\// d' ";
645 do {
646 start += strlen(start) + 1;
647 char* exceptionDirStart = start;
648 if (strncmp(exceptionDirStart, "#\t", 2) != 0) {
649 myassert(exceptionDirStart[0] == '\0');
650 break;
651 }
652 exceptionDirStart += 2;
653 char* exceptionDirEnd = exceptionDirStart;
654 do {
655 exceptionDirEnd = strchr(exceptionDirEnd, '\\');
656 } while (exceptionDirEnd && *++exceptionDirEnd == '/');
657 myassert(exceptionDirEnd);
658 --exceptionDirEnd;
659 myassert(exceptionDirEnd[-1] == ' ');
660 myassert(exceptionDirEnd[-2] == '*');
661 myassert(exceptionDirEnd[-3] == '/');
662 exceptionDirEnd[-3] = '\0';
663 excludedDirs += "-e '/";
664 if (exceptionDirStart[0] == '/')
665 excludedDirs += "\\";
666 excludedDirs += exceptionDirStart;
667 excludedDirs += "\\// d' ";
668 start = exceptionDirEnd;
669 } while (true);
670 *excludedDirsPtr = excludedDirs;
671 }
672 *startPtr = start;
673 // optionally look for android-specific files
674 char* makeEnd = makeFile + *makeSize;
675 do { // find first filename in makefile
676 if (strcmp(start, "# LOCAL_ANDROID_SRC_FILES_INCLUDED := \\") == 0)
677 break;
678 } while ((start += strlen(start) + 1), start < makeEnd);
679 if (start >= makeEnd)
680 return makeFile;
681 start += strlen(start) + 1;
682 string androidFiles = "grep -v -E '";
683 do {
684 myassert(strncmp(start, "#\t", 2) == 0);
685 start += 2;
686 char ch;
687 bool isIdl = strstr(start, "idl \\") != 0;
688 char* lastSlash = strrchr(start, '/') + 1;
689 while ((ch = *start++) != ' ') {
690 if (ch == '*')
691 androidFiles += '.';
692 else if (ch == '.')
693 androidFiles += '\\';
694 androidFiles += ch;
695 if (!isIdl)
696 continue;
697 if (ch == '/' && start == lastSlash)
698 androidFiles += "JS";
699 if (ch == '.') {
700 myassert(strcmp(start, "idl \\") == 0);
701 start += 4;
702 androidFiles += 'h';
703 break;
704 }
705 }
706 androidFiles += "|";
707 myassert(*start == '\\');
708 start += 2;
709 } while (start[0] == '#');
710 androidFiles[androidFiles.size() - 1] = '\'';
711 *androidFilesPtr = androidFiles;
712 return makeFile;
713 }
714
GetDerivedSourcesMake(const char * dir)715 vector<char*> GetDerivedSourcesMake(const char* dir)
716 {
717 vector<char*> result;
718 char scratch[1024];
719 sprintf(scratch, "%s/%s/%s", newBase, dir, "DerivedSources.make");
720 size_t fileSize;
721 char* file = GetFile(scratch, &fileSize);
722 char* fileEnd = file + fileSize;
723 myassert(file);
724 size_t len;
725 do { // find first filename in makefile
726 len = strlen(file);
727 if (strcmp(file, "all : \\") == 0)
728 break;
729 file += len + 1;
730 } while (file < fileEnd);
731 myassert(strcmp(file, "all : \\") == 0);
732 file += len + 1;
733 while (file[0] != '#') {
734 len = strlen(file);
735 char* st = file;
736 skipSpace(&st);
737 if (st[0] != '\\' && st[0] != '$')
738 result.push_back(st);
739 file += len + 1;
740 }
741 return result;
742 }
743
MarkDerivedFound(vector<char * > & derived,char * check,size_t len)744 bool MarkDerivedFound(vector<char*>& derived, char* check, size_t len)
745 {
746 bool found = false;
747 for (unsigned index = 0; index < derived.size(); index++) {
748 char* der = derived[index];
749 if (strncmp(der, check, len) == 0) {
750 der[0] = '\0';
751 found = true;
752 }
753 }
754 return found;
755 }
756
UpdateDerivedMake()757 void UpdateDerivedMake()
758 {
759 const char* dir = "WebCore";
760 int err;
761 vector<char*> derived = GetDerivedSourcesMake(dir);
762 size_t makeSize;
763 char* start, * localStart;
764 string excludedDirs, excludedFiles, excludedGenerated, androidFiles;
765 char* makeFile = GetMakeAndExceptions(dir, "Android.derived.mk", &makeSize,
766 &excludedFiles, &excludedGenerated, &excludedDirs, &androidFiles,
767 &start, &localStart);
768 if (options.emitPerforceCommands)
769 fprintf(commandFile, "p4 edit %s/%s/%s\n", sandboxCmd, dir, "Android.derived.mk");
770 fprintf(commandFile, "cat %s/%s/%s | sed \\\n", sandboxCmd, dir, "Android.derived.mk");
771 string updateDerivedMake = ScratchFile(__FUNCTION__);
772 string filelist = string("cd ") + newBase + "/" + dir +
773 " ; find . -name '*.idl' | " + excludedFiles +
774 " | sed -e 's/.\\///' " + excludedDirs +
775 " | sed 's@\\(.*\\)/\\(.*\\)\\.idl@ $(intermediates)/\\1/JS\\2.h@' "
776 " | sort -o " + updateDerivedMake;
777 err = system(filelist.c_str());
778 myassert(err == 0 || err == 256);
779 char* bindings = GetFile(updateDerivedMake);
780 bool inGen = false;
781 char* fileEnd = makeFile + makeSize;
782 char* nextStart;
783 do {
784 size_t startLen = strlen(start);
785 nextStart = start + startLen + 1;
786 bool onGen = false;
787 char* st = start;
788 if (inGen == false) {
789 if (strncmp(st, "GEN", 3) != 0)
790 continue;
791 st += 3;
792 skipSpace(&st);
793 if (strncmp(st, ":=", 2) != 0)
794 continue;
795 st += 2;
796 onGen = true;
797 }
798 skipSpace(&st);
799 inGen = start[startLen - 1] == '\\';
800 if (inGen) {
801 if (st[0] == '\\' && st[1] == '\0')
802 continue;
803 if (strcmp(st, "$(addprefix $(intermediates)/, \\") == 0)
804 continue;
805 } else if (st[0] == ')' && st[1] == '\0')
806 continue;
807 static const char bindHead[] = "bindings/js/";
808 const size_t bindLen = sizeof(bindHead) - 1;
809 string escaped;
810 if (strncmp(st, bindHead, bindLen) == 0) {
811 st += bindLen;
812 if (MarkDerivedFound(derived, st, strlen(st)) == false) {
813 fprintf(stderr, "*** webkit removed js binding: %s"
814 " (must be removed manually)\n", st);
815 escaped = SedEscape(st);
816 fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
817 }
818 continue;
819 }
820 myassert(strncmp(st, "$(intermediates)", 16) == 0);
821 if (onGen && inGen == false) { // no continuation
822 char* lastSlash;
823 myassert(strrchr(st, '/') != NULL);
824 while ((lastSlash = strrchr(st, '/')) != NULL) {
825 char* lastEnd = strchr(lastSlash, ' ');
826 if (lastEnd == NULL)
827 lastEnd = lastSlash + strlen(lastSlash);
828 myassert(lastSlash != 0);
829 lastSlash++;
830 size_t lastLen = lastEnd - lastSlash;
831 if (MarkDerivedFound(derived, lastSlash, lastLen) == false) {
832 fprintf(stderr, "*** webkit removed generated file:"
833 " %.*s (must be removed manually)\n", (int) lastLen,
834 lastSlash);
835 // escaped = SedEscape(st);
836 // fprintf(commandFile, "-e '/%s/ d' \\\n", escaped.c_str());
837 }
838 char* priorDollar = strrchr(st, '$');
839 myassert(priorDollar != NULL);
840 char* nextDollar = strchr(st, '$');
841 if (nextDollar == priorDollar)
842 break;
843 priorDollar[0] = '\0';
844 }
845 continue;
846 }
847 char* nextSt = nextStart;
848 skipSpace(&nextSt);
849 myassert(strncmp(nextSt, "$(intermediates)", 16) != 0 || strcmp(st, nextSt) < 0);
850 // do {
851 char* bind = bindings;
852 myassert(bind);
853 skipSpace(&bind);
854 int compare = strncmp(bind, st, strlen(bind) - 2);
855 if (compare < 0) { // add a file
856 escaped = SedEscape(st);
857 char* filename = strrchr(bindings, '/');
858 myassert(filename);
859 filename += 3;
860 // FIX ME: exclude items in DerivedSources.make all : $(filter-out ...
861 char* bi = bindings;
862 skipSpace(&bi);
863 char* bindName = strrchr(bi, '/');
864 myassert(bindName != NULL);
865 bindName++;
866 string biStr = SedEscape(bi);
867 fprintf(commandFile, "-e '/%s/ i\\\n_TAB_%s \\\\\n' ",
868 escaped.c_str(), biStr.c_str());
869 MarkDerivedFound(derived, bindName, strlen(bindName));
870 nextStart = start;
871 bindings += strlen(bindings) + 1;
872 inGen = true;
873 } else if (compare > 0) {
874 // if file to be deleted is locally added by android, leave it alone
875 myassert(strncmp(st, "$(intermediates)/", 17) == 0);
876 string subst = string(st).substr(17, strlen(st) - 17 - (inGen ? 2 : 0));
877 string localDerivedStr = ScratchFile("LocalDerived");
878 string filter = string("echo '") + subst + "' | " + androidFiles +
879 " > " + localDerivedStr;
880 if (options.debug)
881 fprintf(stderr, "LocalDerived.txt : %s\n", filter.c_str());
882 err = system(filter.c_str());
883 myassert(err == 0 || err == 256);
884 char* localDerived = GetFile(localDerivedStr);
885 if (localDerived[0] != '\0') {
886 escaped = SedEscape(st);
887 fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
888 }
889 } else {
890 char* stName = strrchr(st, '/');
891 myassert(stName);
892 stName++;
893 MarkDerivedFound(derived, stName, strlen(stName));
894 bindings += strlen(bindings) + 1;
895 }
896 // } while (strstr(start, "$(intermediates)") != NULL);
897 // if changing directories, add any new files to the end of this directory first
898 if (bindings[0] != '\0' && strstr(nextStart, "$(intermediates)") == NULL) {
899 st = start;
900 skipSpace(&st);
901 escaped = SedEscape(st);
902 st = strchr(st, '/');
903 char* stDirEnd = strchr(st + 1, '/');
904 do {
905 bind = strchr(bindings, '/');
906 if (!bind)
907 break;
908 char* bindEnd = strchr(bind + 1, '/');
909 if (!bindEnd)
910 break;
911 if (bindEnd - bind != stDirEnd - st)
912 break;
913 if (strncmp(st, bind, stDirEnd - st) != 0)
914 break;
915 if (inGen == false)
916 fprintf(commandFile, "-e '/%s/ s/$/ \\\\/' ", escaped.c_str());
917 char* bi = bindings;
918 skipSpace(&bi);
919 string biStr = SedEscape(bi);
920 fprintf(commandFile, "-e '/%s/ a\\\n_TAB_%s\n' ",
921 escaped.c_str(), biStr.c_str());
922 MarkDerivedFound(derived, bindEnd + 1, strlen(bindEnd + 1));
923 escaped = biStr;
924 inGen = false;
925 bindings += strlen(bindings) + 1;
926 } while (true);
927 }
928 } while (start = nextStart, start < fileEnd);
929 for (unsigned index = 0; index < derived.size(); index++) {
930 char* der = derived[index];
931 if (der[0] == '\0')
932 continue;
933 string excludedGeneratedStr = ScratchFile("ExcludedGenerated");
934 string filter = string("echo '") + der + "' | " + excludedGenerated +
935 " > " + excludedGeneratedStr;
936 err = system(filter.c_str());
937 myassert(err == 0 || err == 256);
938 char* excluded = GetFile(excludedGeneratedStr);
939 if (excluded[0] != '\0')
940 fprintf(stderr, "*** missing rule to generate %s\n", der);
941 }
942 fprintf(commandFile, " | sed 's/^_TAB_/\t/' > %s/%s/%s\n", sandboxCmd, dir, "xAndroid.derived.mk");
943 fprintf(commandFile, "mv %s/%s/%s %s/%s/%s\n",
944 sandboxCmd, dir, "xAndroid.derived.mk", sandboxCmd, dir, "Android.derived.mk");
945 if (options.emitGitCommands)
946 fprintf(commandFile, "git add %s/%s\n", dir, "Android.derived.mk");
947 }
948
MatchLen(const char * one,const char * two,size_t len)949 int MatchLen(const char* one, const char* two, size_t len)
950 {
951 bool svgIn1 = strstr(one, "svg") || strstr(one, "SVG");
952 bool svgIn2 = strstr(two, "svg") || strstr(two, "SVG");
953 if (svgIn1 != svgIn2)
954 return 0;
955 int signedLen = (int) len;
956 int original = signedLen;
957 while (*one++ == *two++ && --signedLen >= 0)
958 ;
959 return original - signedLen;
960 }
961
962 // create the list of sed commands to update the WebCore Make file
UpdateMake(const char * dir)963 void UpdateMake(const char* dir)
964 {
965 // read in the makefile
966 size_t makeSize;
967 char* start, * localStart = NULL;
968 string excludedDirs, excludedFiles, androidFiles;
969 char* makeFile = GetMakeAndExceptions(dir, "Android.mk", &makeSize,
970 &excludedFiles, NULL, &excludedDirs, &androidFiles, &start, &localStart);
971 char* lastFileName = NULL;
972 size_t lastFileNameLen = 0;
973 int lastLineNumber = -1;
974 // get the actual list of files
975 string updateMakeStr = ScratchFile(__FUNCTION__);
976 string filelist = string("cd ") + newBase + "/" + dir + " ;"
977 " find . -name '*.cpp' -or -name '*.c' -or -name '*.y' | " +
978 excludedFiles + " | sed -e 's/.\\///' " + excludedDirs +
979 " | sort -o " + updateMakeStr;
980 if (options.debug)
981 fprintf(stderr, "make %s/%s filter: %s\n", dir, "Android.mk", filelist.c_str());
982 int err = system(filelist.c_str());
983 myassert(err == 0 || err == 256);
984 char* newList = GetFile(updateMakeStr);
985 do { // find first filename in makefile
986 if (strncmp(start, "LOCAL_SRC_FILES := \\", 20) == 0)
987 break;
988 start += strlen(start) + 1;
989 } while (start < makeFile + makeSize);
990 myassert(start[0] != '\0');
991 if (options.emitPerforceCommands)
992 fprintf(commandFile, "p4 edit %s/%s/%s\n", sandboxCmd, dir, "Android.mk");
993 fprintf(commandFile, "cat %s/%s/%s | sed ", sandboxCmd, dir, "Android.mk");
994 int lineNumber = 0;
995 do {
996 start += strlen(start) + 1;
997 lineNumber++;
998 if (start - makeFile >= makeSize || start[0] == '$')
999 break;
1000 if (start[0] == '\0' || !isspace(start[0]))
1001 continue;
1002 skipSpace(&start);
1003 if (start[0] == '\0' || start[0] == '\\')
1004 continue;
1005 size_t startLen = strlen(start);
1006 if (start[startLen - 1] == '\\')
1007 --startLen;
1008 while (isspace(start[startLen - 1]))
1009 --startLen;
1010 size_t newListLen = strlen(newList);
1011 if (lastFileName != NULL) {
1012 myassert(strncmp(start, lastFileName, startLen) > 0 ||
1013 startLen > lastFileNameLen);
1014 }
1015 if (strstr(start, "android") != NULL || strstr(start, "Android") != NULL) {
1016 if (startLen == newListLen && strncmp(newList, start, startLen) == 0)
1017 newList += newListLen + 1;
1018 lastFileName = start;
1019 lastFileNameLen = startLen;
1020 lastLineNumber = lineNumber;
1021 continue;
1022 }
1023 int compare;
1024 bool backslash = lastFileName &&
1025 lastFileName[strlen(lastFileName) - 1] == '\\';
1026 do {
1027 compare = strncmp(newList, start, startLen);
1028 if (compare == 0 && startLen != newListLen)
1029 compare = newListLen < startLen ? -1 : 1;
1030 if (newList[0] == '\0' || compare >= 0)
1031 break;
1032 // add a file
1033 if (lastFileName && lineNumber - lastLineNumber > 1 &&
1034 MatchLen(lastFileName, newList, lastFileNameLen) >
1035 MatchLen(start, newList, startLen)) {
1036 string escaped = SedEscape(lastFileName);
1037 if (!backslash)
1038 fprintf(commandFile, "-e '/%s/ s/$/ \\\\/' ", escaped.c_str());
1039 fprintf(commandFile, "-e '/%s/ a\\\n_TAB_%s%s\n' ",
1040 SedEscape(lastFileName).c_str(), newList,
1041 backslash ? " \\\\" : "");
1042 lastFileName = newList;
1043 lastFileNameLen = newListLen;
1044 } else {
1045 fprintf(commandFile, "-e '/%s/ i\\\n_TAB_%s \\\\\n' ",
1046 SedEscape(start).c_str(), newList);
1047 }
1048 newList += newListLen + 1;
1049 newListLen = strlen(newList);
1050 } while (true);
1051 if (newList[0] == '\0' || compare > 0) {
1052 // don't delete files added by Android
1053 string localMakeStr = ScratchFile("LocalMake");
1054 string filter = "echo '" + string(start).substr(0, startLen) +
1055 "' | " + androidFiles + " > " + localMakeStr;
1056 int err = system(filter.c_str());
1057 myassert(err == 0 || err == 256);
1058 char* localMake = GetFile(localMakeStr);
1059 if (localMake[0] != '\0') {
1060 string escaped = SedEscape(start);
1061 fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
1062 }
1063 } else
1064 newList += newListLen + 1;
1065 lastFileName = start;
1066 lastFileNameLen = startLen;
1067 lastLineNumber = lineNumber;
1068 } while (true);
1069 fprintf(commandFile, " | sed 's/^_TAB_/\t/' > %s/%s/%s\n", sandboxCmd, dir, "xAndroid.mk");
1070 fprintf(commandFile, "mv %s/%s/%s %s/%s/%s\n",
1071 sandboxCmd, dir, "xAndroid.mk", sandboxCmd, dir, "Android.mk");
1072 if (options.emitGitCommands)
1073 fprintf(commandFile, "git add %s/%s\n", dir, "Android.mk");
1074 }
1075
emptyDirectory(const char * base,const char * work,const char * dir)1076 static bool emptyDirectory(const char* base, const char* work, const char* dir) {
1077 string findEmptyStr = "find \"";
1078 string emptyDirStr = ScratchFile("emptyDirectory");
1079 if (base[0] != '\0')
1080 findEmptyStr += string(base) + "/" + work + "/" + dir + "\"";
1081 else
1082 findEmptyStr += string(work) + "/" + dir + "\"";
1083 findEmptyStr += " -type f -print > " + emptyDirStr;
1084 int err = system(findEmptyStr.c_str());
1085 if (err != 0)
1086 return true;
1087 FILE* file = fopen(emptyDirStr.c_str(), "r");
1088 if (file == NULL)
1089 {
1090 fprintf(stderr, "can't read %s\n", emptyDirStr.c_str());
1091 myassert(0);
1092 return true;
1093 }
1094 fseek(file, 0, SEEK_END);
1095 size_t size = ftell(file);
1096 fclose(file);
1097 return size == 0;
1098 }
1099
emptyDirectory(const char * work,const char * dir)1100 static bool emptyDirectory(const char* work, const char* dir) {
1101 return emptyDirectory("", work, dir);
1102 }
1103
CompareDirs(const char * workingDir,bool renamePass)1104 void CompareDirs(const char* workingDir, bool renamePass)
1105 {
1106 map<string, string> renameMap;
1107 char* oldList = List(oldBase, "old", workingDir);
1108 char* newList = List(newBase, "new", workingDir);
1109 char* sandList = List(sandboxBase, "sandbox", workingDir);
1110 char* oldMem = oldList;
1111 char* newMem = newList;
1112 char* sandboxMem = sandList;
1113 // identify files to be added, removed by comparing old, new lists
1114 do {
1115 size_t oldLen = strlen(oldList);
1116 size_t newLen = strlen(newList);
1117 size_t sandLen = strlen(sandList);
1118 if (oldLen == 0 && newLen == 0 && sandLen == 0)
1119 break;
1120 bool oldDir = false;
1121 bool oldExecutable = false;
1122 if (oldLen > 0) {
1123 char last = oldList[oldLen - 1];
1124 oldDir = last == '/';
1125 oldExecutable = last == '*';
1126 if (oldDir || oldExecutable)
1127 --oldLen;
1128 }
1129 bool newDir = false;
1130 bool newExecutable = false;
1131 if (newLen > 0) {
1132 char last = newList[newLen - 1];
1133 newDir = last == '/';
1134 newExecutable = last == '*';
1135 if (newDir || newExecutable)
1136 --newLen;
1137 }
1138 bool sandDir = false;
1139 bool sandExecutable = false;
1140 if (sandLen > 0) {
1141 char last = sandList[sandLen - 1];
1142 sandDir = last == '/';
1143 sandExecutable = last == '*';
1144 if (sandDir || sandExecutable)
1145 --sandLen;
1146 }
1147 string oldFileStr = string(oldList).substr(0, oldLen);
1148 const char* oldFile = oldFileStr.c_str();
1149 string newFileStr = string(newList).substr(0, newLen);
1150 const char* newFile = newFileStr.c_str();
1151 string sandFileStr = string(sandList).substr(0, sandLen);
1152 const char* sandFile = sandFileStr.c_str();
1153 int order = Compare(oldList, oldLen, newList, newLen);
1154 int sandOrder = 0;
1155 if ((oldLen > 0 || sandLen > 0) && order <= 0) {
1156 sandOrder = Compare(sandList, sandLen, oldList, oldLen);
1157 if (sandOrder > 0 && renamePass == false)
1158 fprintf(stderr, "error: file in old webkit missing from sandbox: %s/%s\n",
1159 workingDir, oldFile);
1160 if (sandOrder < 0 && renamePass == false) {
1161 // file added by android -- should always have name 'android?'
1162 const char* android = strstr(sandFile, "ndroid");
1163 if (android == NULL)
1164 fprintf(stderr, "warning: expect added %s to contain 'android': %s/%s\n",
1165 sandDir ? "directory" : "file" , workingDir, sandFile);
1166 }
1167 if (sandOrder == 0) {
1168 myassert(oldDir == sandDir);
1169 if (oldExecutable != sandExecutable)
1170 CheckForExec(oldBase, workingDir, oldList,
1171 sandboxBase, workingDir, sandList, 0, 0);
1172 }
1173 if (sandOrder <= 0)
1174 sandList += strlen(sandList) + 1;
1175 if (sandOrder < 0)
1176 continue;
1177 }
1178 if (order < 0) { // file in old list is not in new
1179 // check to see if file is read only ; if so, call p4 delete -- otherwise, just call delete
1180 if (oldDir == false) {
1181 bool modifiedFile = false;
1182 // check to see if android modified deleted file
1183 if (sandOrder == 0) {
1184 string rename(workingDir);
1185 rename.append("/");
1186 rename.append(oldFile);
1187 if (renamePass) {
1188 string newName = Find(oldFile);
1189 if (newName.length() > 0) {
1190 map<string, string>::iterator iter = renameMap.find(rename);
1191 myassert(iter == renameMap.end()); // if I see the same file twice, must be a bug
1192 renameMap[rename] = newName;
1193 myassert(rename != newName);
1194 if (options.debug)
1195 fprintf(stderr, "map %s to %s\n", rename.c_str(), newName.c_str());
1196 }
1197 }
1198 if (renamePass == false) {
1199 bool oldSandboxDiff = CompareFiles(oldBase, sandboxBase, workingDir, oldList);
1200 const char* renamedDir = workingDir;
1201 map<string, string>::iterator iter = renameMap.find(rename);
1202 if (iter != renameMap.end()) {
1203 string newName = renameMap[rename];
1204 renamedDir = newName.c_str();
1205 char* renamed = (char*) strrchr(renamedDir, '/');
1206 *renamed++ = '\0'; // splits rename into two strings
1207 if (options.emitPerforceCommands) {
1208 fprintf(commandFile, "p4 integrate \"%s/%s/%s\" \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile,
1209 sandboxCmd, renamedDir, renamed);
1210 fprintf(commandFile, "p4 resolve \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
1211 } else if (options.emitGitCommands) {
1212 fprintf(commandFile, "git mv \"%s/%s\" \"%s/%s\"\n", workingDir, oldFile,
1213 renamedDir, renamed);
1214 }
1215 if (oldSandboxDiff) {
1216 if (options.emitPerforceCommands)
1217 fprintf(commandFile, "p4 open \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
1218 fprintf(commandFile, "merge -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\"\n",
1219 sandboxCmd, renamedDir, renamed, oldCmd, workingDir, oldFile, newCmd, renamedDir, renamed);
1220 bool success = Merge(workingDir, oldFile, renamedDir, renamed, "/dev/null");
1221 if (success == false) {
1222 fprintf(stderr, "*** Manual merge required: %s/%s\n", renamedDir, renamed);
1223 fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e 's/^<<<<<<<.*$/#ifdef MANUAL_MERGE_REQUIRED/' "
1224 "-e 's/^=======$/#else \\/\\/ MANUAL_MERGE_REQUIRED/' "
1225 "-e 's/^>>>>>>>.*$/#endif \\/\\/ MANUAL_MERGE_REQUIRED/' > \"%s/%s/x%s\"\n",
1226 sandboxCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
1227 fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
1228 sandboxCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
1229 }
1230 if (options.emitGitCommands)
1231 fprintf(commandFile, "git add \"%s/%s\"\n", renamedDir, renamed);
1232 } else {
1233 bool oldNewDiff = CompareFiles(oldBase, workingDir, oldList, newBase, renamedDir, renamed);
1234 if (oldNewDiff) {
1235 if (options.emitPerforceCommands)
1236 fprintf(oopsFile, "p4 open \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
1237 fprintf(oopsFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n",
1238 newCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
1239 if (options.emitGitCommands)
1240 fprintf(oopsFile, "git add \"%s/%s\"\n", renamedDir, renamed);
1241 }
1242 }
1243 } else if (oldSandboxDiff) {
1244 modifiedFile = true;
1245 fprintf(stderr, "*** Modified file deleted: %s/%s\n", workingDir, oldFile);
1246 // FindDeletedAndroidChanges(workingDir, oldFile);
1247 }
1248 } // if renamePass == false
1249 } // if sandOrder == 0
1250 if (modifiedFile) {
1251 fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e '1 i\\\n#ifdef MANUAL_MERGE_REQUIRED\n' "
1252 "-e '$ a\\\n#endif \\/\\/ MANUAL_MERGE_REQUIRED\n' > \"%s/%s/x%s\"\n",
1253 sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1254 fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
1255 sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1256 } else if (options.emitPerforceCommands)
1257 fprintf(commandFile, "p4 delete \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
1258 else if (options.emitGitCommands)
1259 fprintf(commandFile, "git rm \"%s/%s\"\n", workingDir, oldFile);
1260 else
1261 fprintf(commandFile, "rm \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
1262 } else { // if oldDir != false
1263 // !!! FIXME start here;
1264 // check to see if old directory is empty ... (e.g., WebCore/doc)
1265 // ... and/or isn't in sandbox anyway (e.g., WebCore/LayoutTests)
1266 // if old directory is in sandbox (e.g. WebCore/kcanvas) that should work
1267 if (options.emitPerforceCommands)
1268 fprintf(commandFile, "p4 delete \"%s/%s/%s/...\"\n", sandboxCmd, workingDir, oldFile);
1269 else if (options.emitGitCommands)
1270 fprintf(commandFile, "git rm \"%s/%s/...\"\n", workingDir, oldFile);
1271 else
1272 fprintf(commandFile, "rm \"%s/%s/%s/...\"\n", sandboxCmd, workingDir, oldFile);
1273 if (renamePass == false)
1274 fprintf(stderr, "*** Directory deleted: %s/%s\n", workingDir, oldFile);
1275 }
1276 oldList += strlen(oldList) + 1;
1277 continue;
1278 }
1279 if (order > 0) {
1280 if (renamePass == false) {
1281 string rename(workingDir);
1282 rename.append("/");
1283 rename.append(newFile);
1284 bool skip = false;
1285 for (map<string, string>::iterator iter = renameMap.begin(); iter != renameMap.end(); iter++) {
1286 if (iter->second == rename) {
1287 skip = true;
1288 break;
1289 }
1290 }
1291 if (skip == false) {
1292 if (newDir) {
1293 if (strcmp(sandFile, newFile) != 0 &&
1294 emptyDirectory(newBase, workingDir, newFile) == false) {
1295 fprintf(copyDirFile, "find \"%s/%s/%s\" -type d -print | "
1296 "sed 's@%s/\\(.*\\)@mkdir %s/\\1@' | bash -s\n",
1297 newCmd, workingDir, newFile, newCmd, sandboxCmd);
1298 fprintf(copyDirFile, "find \"%s/%s/%s\" -type f -print | "
1299 "sed 's@%s/\\(.*\\)@cp %s/\\1 %s/\\1@' | bash -s\n",
1300 newCmd, workingDir, newFile, newCmd, newCmd, sandboxCmd);
1301 if (options.emitPerforceCommands)
1302 fprintf(copyDirFile, "find \"%s/%s/%s\" -type f -print | "
1303 "p4 -x - add\n",
1304 sandboxCmd, workingDir, newFile);
1305 else if (options.emitGitCommands)
1306 fprintf(copyDirFile, "git add \"%s/%s\"\n",
1307 workingDir, newFile);
1308 }
1309 } else {
1310 // if (emptyDirectory(sandboxBase, workingDir)) {
1311 // fprintf(commandFile, "mkdir \"%s/%s\"\n", sandboxCmd, workingDir);
1312 // }
1313 bool edit = false;
1314 size_t newLen1 = strlen(newFile);
1315 for (map<string, string>::iterator iter = renameMap.begin(); iter != renameMap.end(); iter++) {
1316 if (strcmp(iter->second.c_str(), workingDir) == 0) {
1317 const char* first = iter->first.c_str();
1318 size_t firstLen = strlen(first);
1319 if (firstLen > newLen1 && strcmp(newFile,
1320 &first[firstLen - newLen1]) == 0) {
1321 edit = true;
1322 break;
1323 }
1324 }
1325 }
1326 if (edit == false) {
1327 fprintf(commandFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n",
1328 newCmd, workingDir, newFile, sandboxCmd, workingDir, newFile);
1329 if (options.emitPerforceCommands)
1330 fprintf(commandFile, "p4 add \"%s/%s/%s\"\n", sandboxCmd, workingDir, newFile);
1331 else if (options.emitGitCommands)
1332 fprintf(commandFile, "git add \"%s/%s\"\n", workingDir, newFile);
1333 }
1334 }
1335 }
1336 }
1337 newList += strlen(newList) + 1;
1338 continue;
1339 }
1340 if (oldDir) {
1341 myassert(newDir);
1342 size_t newLen1 = strlen(workingDir) + strlen(oldList);
1343 char* newFile = new char[newLen1 + 1];
1344 sprintf(newFile, "%s/%.*s", workingDir, (int) strlen(oldList) - 1,
1345 oldList);
1346 if (sandOrder > 0) { // file is on old and new but not sandbox
1347 if (emptyDirectory(newBase, newFile) == false) {
1348 fprintf(copyDirFile, "find \"%s/%s\" -type d -print | "
1349 "sed 's@%s/\\(.*\\)@mkdir %s/\\1@' | bash -s\n",
1350 newCmd, newFile, newCmd, sandboxCmd);
1351 fprintf(copyDirFile, "find \"%s/%s\" -type f -print | "
1352 "sed 's@%s/\\(.*\\)@cp %s/\\1 %s/\\1@' | bash -s\n",
1353 newCmd, newFile, newCmd, newCmd, sandboxCmd);
1354 if (options.emitPerforceCommands)
1355 fprintf(copyDirFile, "find \"%s/%s\" -type f -print | "
1356 "p4 -x - add\n",
1357 sandboxCmd, newFile);
1358 else if (options.emitGitCommands)
1359 fprintf(copyDirFile, "git add \"%s\"", newFile);
1360 }
1361 } else
1362 CompareDirs(newFile, renamePass);
1363 delete[] newFile;
1364 } else {
1365 // at this point, the file is in both old and new webkits; see if it changed
1366 // ignore executables, different or not (or always copy, or do text compare? or find binary compare? )
1367 if (oldExecutable != newExecutable)
1368 fprintf(stderr, "*** %s/%s differs in the execute bit (may cause problems for perforce)\n", workingDir, oldFile);
1369 // myassert(sandOrder != 0 || sandFile[sandLen - 1] == '*');
1370 // Diff(oldBase, sandboxBase, workingDir, oldFile);
1371 bool oldNewDiff = CompareFiles(oldBase, newBase, workingDir, oldList);
1372 if (oldNewDiff && sandOrder == 0 && renamePass == false) { // if it changed, see if android also changed it
1373 if (options.emitPerforceCommands)
1374 fprintf(commandFile, "p4 edit \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
1375 bool oldSandboxDiff = CompareFiles(oldBase, sandboxBase, workingDir, oldFile);
1376 if (oldSandboxDiff) {
1377 fprintf(commandFile, "merge -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\"\n",
1378 sandboxCmd, workingDir, oldFile, oldCmd, workingDir, oldFile, newCmd, workingDir, oldFile);
1379 bool success = Merge(workingDir, oldFile);
1380 if (success == false) {
1381 fprintf(stderr, "*** Manual merge required: %s/%s\n", workingDir, oldFile);
1382 fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e 's/^<<<<<<<.*$/#ifdef MANUAL_MERGE_REQUIRED/' "
1383 "-e 's/^=======$/#else \\/\\/ MANUAL_MERGE_REQUIRED/' -e 's/^>>>>>>>.*$/#endif \\/\\/ MANUAL_MERGE_REQUIRED/' > \"%s/%s/x%s\"\n",
1384 sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1385 fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
1386 sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
1387 }
1388 } else fprintf(commandFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n", newCmd, workingDir, oldFile ,
1389 sandboxCmd, workingDir, oldFile);
1390 if (options.emitGitCommands)
1391 fprintf(commandFile, "git add \"%s/%s\"\n", workingDir, oldFile);
1392 }
1393 }
1394 myassert(oldLen == newLen);
1395 newList += strlen(newList) + 1;
1396 oldList += strlen(oldList) + 1;
1397 } while (true);
1398 delete[] oldMem;
1399 delete[] newMem;
1400 delete[] sandboxMem;
1401 }
1402
Ignore(char * fileName,size_t len)1403 bool Ignore(char* fileName, size_t len)
1404 {
1405 if (len == 0)
1406 return true;
1407 if (fileName[len - 1] =='/')
1408 return true;
1409 if (strcmp(fileName, ".DS_Store") == 0)
1410 return true;
1411 if (strcmp(fileName, ".ignoreSVN") == 0)
1412 return true;
1413 return false;
1414 }
1415
FixStar(char * fileName,size_t len)1416 void FixStar(char* fileName, size_t len)
1417 {
1418 if (fileName[len - 1] =='*')
1419 fileName[len - 1] = '\0';
1420 }
1421
FixColon(char ** fileNamePtr,size_t * lenPtr)1422 void FixColon(char** fileNamePtr, size_t* lenPtr)
1423 {
1424 char* fileName = *fileNamePtr;
1425 size_t len = *lenPtr;
1426 if (fileName[len - 1] !=':')
1427 return;
1428 fileName[len - 1] = '\0';
1429 if (strncmp(fileName ,"./", 2) != 0)
1430 return;
1431 fileName += 2;
1432 *fileNamePtr = fileName;
1433 len -= 2;
1434 *lenPtr = len;
1435 }
1436
IgnoreDirectory(const char * dir,const char ** dirList)1437 bool IgnoreDirectory(const char* dir, const char** dirList)
1438 {
1439 if (dirList == NULL)
1440 return false;
1441 const char* test;
1442 while ((test = *dirList++) != NULL) {
1443 if (strncmp(dir, test, strlen(test)) == 0)
1444 return true;
1445 }
1446 return false;
1447 }
1448
doSystem(char * scratch)1449 static void doSystem(char* scratch)
1450 {
1451 if (false) printf("%s\n", scratch);
1452 int err = system(scratch);
1453 myassert(err == 0);
1454 }
1455
copyToCommand(char * scratch,string file)1456 static void copyToCommand(char* scratch, string file)
1457 {
1458 doSystem(scratch);
1459 char* diff = GetFile(file.c_str());
1460 while (*diff) {
1461 fprintf(commandFile, "%s\n", diff);
1462 diff += strlen(diff) + 1;
1463 }
1464 }
1465
1466 #define WEBKIT_EXCLUDED_DIRECTORIES \
1467 "-not -path \"*Tests\" " /* includes LayoutTests, PageLoadTests */ \
1468 "-not -path \"*Tests/*\" " /* includes LayoutTests, PageLoadTests */ \
1469 "-not -path \"*Site\" " /* includes BugsSite, WebKitSite */ \
1470 "-not -path \"*Site/*\" " /* includes BugsSite, WebKitSite */ \
1471 "-not -path \"./PlanetWebKit/*\" " \
1472 "-not -path \"./PlanetWebKit\" "
1473
1474 #define ANDROID_EXCLUDED_FILES \
1475 "-e '/^Files .* differ/ d' " \
1476 "-e '/^Only in .*/ d' " \
1477 "-e '/Android.mk/ d' " \
1478 "-e '/android$/ d' "
1479
1480 #define ANDROID_EXCLUDED_DIRS \
1481 "-e '/\\/JavaScriptCore\\// d' " \
1482 "-e '/\\/WebCore\\// d' "
1483
1484 #define ANDROID_EXCLUDED_DIRS_GIT \
1485 "-e '/ JavaScriptCore\\// d' " \
1486 "-e '/ WebCore\\// d' "
1487
CopyOther()1488 void CopyOther()
1489 {
1490 string excludedFiles = ANDROID_EXCLUDED_FILES;
1491 if (options.emitGitCommands)
1492 excludedFiles += ANDROID_EXCLUDED_DIRS_GIT;
1493 else
1494 excludedFiles += ANDROID_EXCLUDED_DIRS;
1495 char scratch[1024];
1496 // directories to ignore in webkit
1497 string copyOtherWebKit = ScratchFile("CopyOtherWebKit");
1498 sprintf(scratch, "cd %s ; find . -type d -not -empty "
1499 WEBKIT_EXCLUDED_DIRECTORIES
1500 " > %s", newBase, copyOtherWebKit.c_str());
1501 doSystem(scratch);
1502 // directories to ignore in android
1503 string copyOtherAndroid = ScratchFile("CopyOtherAndroid");
1504 sprintf(scratch, "cd %s ; find . -type d -not -empty "
1505 "-not -path \"*.git*\" "
1506 "-not -path \"*android*\" "
1507 " > %s", sandboxBase, copyOtherAndroid.c_str());
1508 doSystem(scratch);
1509 if (0) {
1510 string copyOtherMkDir = ScratchFile("CopyOtherMkDir");
1511 sprintf(scratch, "diff %s %s | sed -e 's@< \\./\\(.*\\)$"
1512 "@mkdir %s/\\1@' "
1513 "-e '/^[0-9].*/ d' "
1514 "-e '/>.*/ d' "
1515 "-e '/---/ d' "
1516 "-e '/\\/JavaScriptCore\\// d' "
1517 "-e '/\\/WebCore\\// d' "
1518 "> %s", copyOtherWebKit.c_str(), copyOtherAndroid.c_str(), sandboxCmd,
1519 copyOtherMkDir.c_str());
1520 if (options.debug)
1521 fprintf(stderr, "%s\n", scratch);
1522 copyToCommand(scratch, copyOtherMkDir);
1523 }
1524 string copyOtherDiff = ScratchFile("CopyOtherDiff");
1525 int scratchLen = sprintf(scratch, "diff %s %s | sed -e 's@< \\./\\(.*\\)$"
1526 "@mkdir -p -v %s/\\1 ; find %s/\\1 -type f -depth 1 -exec cp {} %s/\\1 \";\"",
1527 copyOtherWebKit.c_str(), copyOtherAndroid.c_str(), sandboxCmd, newCmd,
1528 sandboxCmd);
1529 if (options.emitGitCommands)
1530 scratchLen += sprintf(&scratch[scratchLen], " ; cd %s ; find ", sandboxCmd);
1531 else
1532 scratchLen += sprintf(&scratch[scratchLen], " ; find %s/", sandboxCmd);
1533 scratchLen += sprintf(&scratch[scratchLen], "\\1 -type f -depth 1 | ");
1534 if (options.emitPerforceCommands)
1535 scratchLen += sprintf(&scratch[scratchLen], "p4 -x - add ");
1536 else if (options.emitGitCommands)
1537 scratchLen += sprintf(&scratch[scratchLen], "xargs git add ");
1538 scratchLen += sprintf(&scratch[scratchLen],
1539 "@' -e '/^[0-9].*/ d' "
1540 "-e '/>.*/ d' "
1541 "-e '/---/ d' "
1542 "-e '/\\/JavaScriptCore\\// d' "
1543 "-e '/\\/WebCore\\// d' "
1544 "> %s", copyOtherDiff.c_str());
1545 if (options.debug)
1546 fprintf(stderr, "%s\n", scratch);
1547 copyToCommand(scratch, copyOtherDiff);
1548 string deleteOtherDiff = ScratchFile("DeleteOtherDiff");
1549 scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
1550 "'s@Only in %s/\\(.*\\)\\: \\(.*\\)@",
1551 newBase, sandboxBase, sandboxBase);
1552 if (options.emitPerforceCommands)
1553 scratchLen += sprintf(&scratch[scratchLen], "p4 delete %s/", sandboxCmd);
1554 else if (options.emitGitCommands)
1555 scratchLen += sprintf(&scratch[scratchLen], "git rm ");
1556 else
1557 scratchLen += sprintf(&scratch[scratchLen], "rm %s/", sandboxCmd);
1558 scratchLen += sprintf(&scratch[scratchLen], "\\1/\\2@' %s > %s",
1559 excludedFiles.c_str(), deleteOtherDiff.c_str());
1560 if (options.debug)
1561 fprintf(stderr, "%s\n", scratch);
1562 copyToCommand(scratch, deleteOtherDiff);
1563 string addOtherDiff = ScratchFile("AddOtherDiff");
1564 scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
1565 "'s@Only in %s/\\(.*\\)\\: \\(.*\\)"
1566 "@mkdir -p -v %s/\\1 ; cp %s/\\1/\\2 %s/\\1/\\2 ; ",
1567 newBase, sandboxBase, newBase, sandboxCmd, newCmd, sandboxCmd);
1568 if (options.emitPerforceCommands)
1569 scratchLen += sprintf(&scratch[scratchLen],
1570 "p4 add %s/\\1/\\2", sandboxCmd);
1571 else if (options.emitGitCommands)
1572 scratchLen += sprintf(&scratch[scratchLen],
1573 "git add \\1/\\2");
1574 scratchLen += sprintf(&scratch[scratchLen], "@' %s > %s",
1575 excludedFiles.c_str(), addOtherDiff.c_str());
1576 if (options.debug)
1577 fprintf(stderr, "%s\n", scratch);
1578 copyToCommand(scratch, addOtherDiff);
1579 string editOtherDiff = ScratchFile("EditOtherDiff");
1580 scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
1581 "'s@Files %s/\\(.*\\) and %s/\\(.*\\) differ@",
1582 newBase, sandboxBase, newBase, sandboxBase);
1583 if (options.emitPerforceCommands)
1584 scratchLen += sprintf(&scratch[scratchLen],
1585 "p4 edit %s/\\2 ; ", sandboxCmd);
1586 scratchLen += sprintf(&scratch[scratchLen], "cp %s/\\1 %s/\\2 ",
1587 newCmd, sandboxCmd);
1588 if (options.emitGitCommands)
1589 scratchLen += sprintf(&scratch[scratchLen],
1590 " ; git add \\2");
1591 scratchLen += sprintf(&scratch[scratchLen], "@' %s > %s",
1592 excludedFiles.c_str(), editOtherDiff.c_str());
1593 if (options.debug)
1594 fprintf(stderr, "%s\n", scratch);
1595 copyToCommand(scratch, editOtherDiff);
1596 }
1597
MakeExecutable(const string & filename)1598 void MakeExecutable(const string& filename)
1599 {
1600 string makeExScript = "chmod +x ";
1601 makeExScript += filename;
1602 int err = system(makeExScript.c_str());
1603 myassert(err == 0);
1604 }
1605
ReadArgs(char * const args[],int argCount)1606 bool ReadArgs(char* const args[], int argCount)
1607 {
1608 int index = 0;
1609 const char* toolpath = args[index++];
1610 // first arg is path to this executable
1611 // use this to build default paths
1612
1613 for (; index < argCount; index++) {
1614 const char* arg = args[index];
1615 if (strncmp(arg, "-a", 2) == 0 || strcmp(arg, "--android") == 0) {
1616 index++;
1617 options.androidWebKit = args[index];
1618 continue;
1619 }
1620 if (strncmp(arg, "-b", 2) == 0 || strcmp(arg, "--basewebkit") == 0) {
1621 index++;
1622 options.baseWebKit = args[index];
1623 continue;
1624 }
1625 if (strncmp(arg, "-c", 2) == 0 || strcmp(arg, "--mergecore") == 0) {
1626 options.clearOnce();
1627 options.mergeCore = true;
1628 continue;
1629 }
1630 if (strncmp(arg, "-d", 2) == 0 || strcmp(arg, "--debug") == 0) {
1631 options.debug = true;
1632 continue;
1633 }
1634 if (strncmp(arg, "-e", 2) == 0 || strcmp(arg, "--emptydirs") == 0) {
1635 options.clearOnce();
1636 options.removeEmptyDirs = true;
1637 continue;
1638 }
1639 if (strncmp(arg, "-g", 2) == 0 || strcmp(arg, "--git") == 0) {
1640 options.emitGitCommands = true;
1641 if (options.emitPerforceCommands == false)
1642 continue;
1643 }
1644 if (strncmp(arg, "-m", 2) == 0 || strcmp(arg, "--mergemake") == 0) {
1645 options.clearOnce();
1646 options.mergeMake = true;
1647 continue;
1648 }
1649 if (strncmp(arg, "-n", 2) == 0 || strcmp(arg, "--newwebkit") == 0) {
1650 index++;
1651 options.newWebKit = args[index];
1652 continue;
1653 }
1654 if (strncmp(arg, "-o", 2) == 0 || strcmp(arg, "--copyother") == 0) {
1655 options.clearOnce();
1656 options.copyOther = true;
1657 continue;
1658 }
1659 if (strncmp(arg, "-p", 2) == 0 || strcmp(arg, "--perforce") == 0) {
1660 options.emitPerforceCommands = true;
1661 if (options.emitGitCommands == false)
1662 continue;
1663 }
1664 if (strncmp(arg, "-s", 2) == 0 || strcmp(arg, "--removesvn") == 0) {
1665 options.clearOnce();
1666 options.removeSVNDirs = true;
1667 continue;
1668 }
1669 if (strncmp(arg, "-v", 2) == 0 || strcmp(arg, "--verbose") == 0) {
1670 options.verbose = true;
1671 fprintf(stderr, "path: %s\n", toolpath);
1672 int err = system("pwd > pwd.txt");
1673 myassert(err != -1);
1674 fprintf(stderr, "pwd: %s\n", GetFile("pwd.txt"));
1675 system("rm pwd.txt");
1676 continue;
1677 }
1678 if (strncmp(arg, "-x", 2) == 0 || strcmp(arg, "--execute") == 0) {
1679 options.execute = true;
1680 continue;
1681 }
1682 if (options.emitGitCommands && options.emitPerforceCommands)
1683 printf("choose one of --git and --perforce\n");
1684 else if (strncmp(arg, "-h", 2) != 0 && strcmp(arg, "--help") != 0 && strcmp(arg, "-?") != 0)
1685 printf("%s not understood\n", args[index]);
1686 printf(
1687 "WebKit Merge for Android version 1.1\n"
1688 "Usage: webkitmerge -a path -b path -n path [-g or -p] [-c -d -e -m -o -s -v -x]\n"
1689 "Options -c -e -m -o -s are set unless one or more are passed.\n"
1690 "Leave -g and -p unset to copy, merge, and delete files outside of source control.\n"
1691 "-a --android path Set the Android webkit path to merge to.\n"
1692 "-b --basewebkit path Set the common base for Android and the newer webkit.\n"
1693 "-c --mergecore Create merge scripts for WebCore, JavaScriptCore .h .cpp.\n"
1694 "-d --debug Show debugging printfs; loop forever on internal assert.\n"
1695 "-e --emptydirs Remove empty directories from webkit trees.\n"
1696 "-g --git Emit git commands.\n"
1697 "-h --help Show this help.\n"
1698 "-m --mergemake Create merge scripts for WebCore/Android.mk,\n"
1699 " WebCore/Android.derived.mk, and JavaScriptCore/Android.mk.\n"
1700 "-n --newwebkit path Set the webkit to merge from.\n"
1701 "-o --copyother Create script to copy other webkit directories.\n"
1702 "-p --perforce Emit perforce commands.\n"
1703 "-s --removesvn Remove svn directories from webkit trees.\n"
1704 "-v --verbose Show status printfs.\n"
1705 "-x --execute Execute the merge scripts.\n"
1706 );
1707 return false;
1708 }
1709 return options.finish();
1710 }
1711
main(int argCount,char * const args[])1712 int main (int argCount, char* const args[])
1713 {
1714 if (ReadArgs(args, argCount) == false)
1715 return 0;
1716 int err;
1717 // First remove all .svn directories
1718 if (options.removeSVNDirs) {
1719 if (options.verbose)
1720 fprintf(stderr, "removing svn directories from %s\n", newBase);
1721 string removeSVNStr = string("find ") + newBase +
1722 " -type d -name \".svn\" -print0 | xargs -0 rm -rf";
1723 err = system(removeSVNStr.c_str());
1724 myassert(err == 0);
1725 }
1726 // Remove all empty directories
1727 if (options.removeEmptyDirs) {
1728 if (options.verbose)
1729 fprintf(stderr, "removing empty directories from %s, %s\n",
1730 oldBase, newBase);
1731 string removeEmpty = string("find ") + oldBase + " " + newBase +
1732 " -type d -empty -delete";
1733 err = system(removeEmpty.c_str());
1734 myassert(err == 0);
1735 }
1736 if (options.mergeCore /* || options.mergeMake */) {
1737 if (options.verbose)
1738 fprintf(stderr, "building rename map\n");
1739 commandFile = fopen("/dev/null", "w");
1740 copyDirFile = fopen("/dev/null", "w");
1741 CompareDirs("WebCore", true); // build rename map
1742 CompareDirs("JavaScriptCore", true);
1743 fclose(copyDirFile);
1744 fclose(commandFile);
1745 }
1746 if (options.mergeMake) {
1747 if (options.verbose)
1748 fprintf(stderr, "building make.sh\n");
1749 string makeShell = outputDir + "make.sh";
1750 commandFile = fopen(makeShell.c_str(), "w");
1751 if (options.emitGitCommands || options.emitPerforceCommands)
1752 fprintf(commandFile, "cd %s\n", sandboxCmd);
1753 UpdateMake("WebCore");
1754 UpdateMake("JavaScriptCore");
1755 UpdateDerivedMake();
1756 fclose(commandFile);
1757 MakeExecutable(makeShell);
1758 }
1759 if (options.copyOther) {
1760 if (options.verbose)
1761 fprintf(stderr, "building copyOther.sh\n");
1762 string copyOtherShell = outputDir + "copyOther.sh";
1763 commandFile = fopen(copyOtherShell.c_str(), "w");
1764 if (options.emitGitCommands || options.emitPerforceCommands)
1765 fprintf(commandFile, "cd %s\n", sandboxCmd);
1766 CopyOther();
1767 fclose(commandFile);
1768 MakeExecutable(copyOtherShell);
1769 }
1770 if (options.mergeCore) {
1771 if (options.verbose)
1772 fprintf(stderr, "building command.sh copyDir.sh oops.sh\n");
1773 string commandShell = outputDir + "command.sh";
1774 commandFile = fopen(commandShell.c_str(), "w");
1775 if (options.emitGitCommands || options.emitPerforceCommands)
1776 fprintf(commandFile, "cd %s\n", sandboxCmd);
1777 string copyDirShell = outputDir + "copyDir.sh";
1778 copyDirFile = fopen(copyDirShell.c_str(), "w");
1779 if (options.emitGitCommands || options.emitPerforceCommands)
1780 fprintf(copyDirFile, "cd %s\n", sandboxCmd);
1781 string oopsShell = outputDir + "oops.sh";
1782 oopsFile = fopen(oopsShell.c_str(), "w");
1783 if (options.emitGitCommands || options.emitPerforceCommands)
1784 fprintf(oopsFile, "cd %s\n", sandboxCmd);
1785 CompareDirs("WebCore", false); // generate command script
1786 CompareDirs("JavaScriptCore", false);
1787 fclose(oopsFile);
1788 fclose(copyDirFile);
1789 fclose(commandFile);
1790 MakeExecutable(oopsShell);
1791 MakeExecutable(copyDirShell);
1792 MakeExecutable(commandShell);
1793 }
1794 if (options.execute) {
1795 if (options.mergeCore) {
1796 if (options.verbose)
1797 fprintf(stderr, "executing command.sh\n");
1798 string execCommand = "cd " + options.androidWebKit + "; . " + outputDir + "command.sh";
1799 err = system(execCommand.c_str());
1800 myassert(err == 0);
1801 if (options.verbose)
1802 fprintf(stderr, "executing copyDir.sh\n");
1803 string execCopy = "cd " + options.androidWebKit + "; . " + outputDir + "copyDir.sh";
1804 err = system(execCopy.c_str());
1805 myassert(err == 0);
1806 }
1807 if (options.mergeMake) {
1808 if (options.verbose)
1809 fprintf(stderr, "executing make.sh\n");
1810 string execMake = "cd " + options.androidWebKit + "; . " + outputDir + "make.sh";
1811 err = system(execMake.c_str());
1812 myassert(err == 0);
1813 }
1814 if (options.copyOther) {
1815 if (options.verbose)
1816 fprintf(stderr, "executing copyOther.sh\n");
1817 string execCopyOther = "cd " + options.androidWebKit + "; . " + outputDir + "copyOther.sh";
1818 err = system(execCopyOther.c_str());
1819 myassert(err == 0);
1820 }
1821 }
1822 if (options.verbose)
1823 fprintf(stderr, "done!\n");
1824 else {
1825 string rmAllCmd = "rm " + scratchDir + "* ; rmdir " + scratchDir;
1826 err = system(rmAllCmd.c_str());
1827 myassert(err == 0);
1828 }
1829 return 0;
1830 }
1831
1832 /* things to do:
1833 when inserting MANUAL_MERGE_REQUIRED, if contents is #preprocessor, balance first?
1834 */
1835