X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=buildtool.cpp;h=2b4307ab0f0e2ca6026a7eabc2a4a874d0d32a8b;hb=338d6dce719c1981c663a900b95754114934d3ec;hp=12f3d63e7c13fdfbef0502e083f3ee1a2f4174d9;hpb=6984acdc26f8a933f70ad15ff5421e9f63eaaadc;p=inkscape.git diff --git a/buildtool.cpp b/buildtool.cpp index 12f3d63e7..2b4307ab0 100644 --- a/buildtool.cpp +++ b/buildtool.cpp @@ -3,6 +3,7 @@ * * Authors: * Bob Jamison + * Jasper van de Gronde * * Copyright (C) 2006-2008 Bob Jamison * @@ -38,7 +39,7 @@ * */ -#define BUILDTOOL_VERSION "BuildTool v0.9.1" +#define BUILDTOOL_VERSION "BuildTool v0.9.9" #include #include @@ -54,6 +55,8 @@ #include #include #include +#include + #ifdef __WIN32__ #include @@ -204,7 +207,7 @@ TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp); #include //#include "trex.h" -#ifdef _UINCODE +#ifdef _UNICODE #define scisprint iswprint #define scstrlen wcslen #define scprintf wprintf @@ -688,7 +691,7 @@ static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *s return cur; } case OP_WB: - if(str == exp->_bol && !isspace(*str) + if((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str-1))) || (!isspace(*str) && isspace(*(str+1))) || (isspace(*str) && !isspace(*(str+1))) ) { @@ -2739,6 +2742,98 @@ bool URI::parse(const String &str) //######################################################################## //######################################################################## +//######################################################################## +//# Stat cache to speed up stat requests +//######################################################################## +struct StatResult { + int result; + struct stat statInfo; +}; +typedef std::map statCacheType; +static statCacheType statCache; +static int cachedStat(const String &f, struct stat *s) { + //printf("Stat path: %s\n", f.c_str()); + std::pair result = statCache.insert(statCacheType::value_type(f, StatResult())); + if (result.second) { + result.first->second.result = stat(f.c_str(), &(result.first->second.statInfo)); + } + *s = result.first->second.statInfo; + return result.first->second.result; +} +static void removeFromStatCache(const String f) { + //printf("Removing from cache: %s\n", f.c_str()); + statCache.erase(f); +} + +//######################################################################## +//# Dir cache to speed up dir requests +//######################################################################## +/*struct DirListing { + bool available; + std::vector files; + std::vector dirs; +}; +typedef std::map dirCacheType; +static dirCacheType dirCache; +static const DirListing &cachedDir(String fullDir) +{ + String dirNative = getNativePath(fullDir); + std::pair result = dirCache.insert(dirCacheType::value_type(dirNative, DirListing())); + if (result.second) { + DIR *dir = opendir(dirNative.c_str()); + if (!dir) + { + error("Could not open directory %s : %s", + dirNative.c_str(), strerror(errno)); + result.first->second.available = false; + } + else + { + result.first->second.available = true; + while (true) + { + struct dirent *de = readdir(dir); + if (!de) + break; + + //Get the directory member name + String s = de->d_name; + if (s.size() == 0 || s[0] == '.') + continue; + String childName; + if (dirName.size()>0) + { + childName.append(dirName); + childName.append("/"); + } + childName.append(s); + String fullChild = baseDir; + fullChild.append("/"); + fullChild.append(childName); + + if (isDirectory(fullChild)) + { + //trace("directory: %s", childName.c_str()); + if (!listFiles(baseDir, childName, res)) + return false; + continue; + } + else if (!isRegularFile(fullChild)) + { + error("unknown file:%s", childName.c_str()); + return false; + } + + //all done! + res.push_back(childName); + + } + closedir(dir); + } + } + return result.first->second; +}*/ + //######################################################################## //# F I L E S E T //######################################################################## @@ -2776,7 +2871,7 @@ public: /** * */ - String getDirectory() + String getDirectory() const { return directory; } /** @@ -2794,7 +2889,7 @@ public: /** * */ - std::vector getFiles() + std::vector getFiles() const { return files; } /** @@ -2806,7 +2901,7 @@ public: /** * */ - std::vector getIncludes() + std::vector getIncludes() const { return includes; } /** @@ -2818,19 +2913,19 @@ public: /** * */ - std::vector getExcludes() + std::vector getExcludes() const { return excludes; } /** * */ - unsigned int size() + unsigned int size() const { return files.size(); } /** * */ - String operator[](int index) + String operator[](int index) const { return files[index]; } /** @@ -3094,11 +3189,19 @@ protected: /** * If this prefix is seen in a substitution, use as a * pkg-config 'libs' query - * example: + * example: * ${pcl.gtkmm} */ String pclPrefix; + /** + * If this prefix is seen in a substitution, use as a + * Bazaar "bzr revno" query + * example: ??? + * ${bzr.Revision} + */ + String bzrPrefix; + @@ -3242,6 +3345,16 @@ protected: */ bool copyFile(const String &srcFile, const String &destFile); + /** + * Delete a file + */ + bool removeFile(const String &file); + + /** + * Tests if the file exists + */ + bool fileExists(const String &fileName); + /** * Tests if the file exists and is a regular file */ @@ -3309,10 +3422,10 @@ public: */ PkgConfig() { - path = "."; - prefix = "/target"; - init(); - } + path = "."; + prefix = "/target"; + init(); + } /** * @@ -3527,6 +3640,138 @@ private: int parselen; }; +/** + * Execute the "bzr revno" command and return the result. + * This is a simple, small class. + */ +class BzrRevno : public MakeBase +{ +public: + + /** + * Safe way. Execute "bzr revno" and return the result. + * Safe from changes in format. + */ + bool query(String &res) + { + String cmd = "bzr revno"; + + String outString, errString; + bool ret = executeCommand(cmd.c_str(), "", outString, errString); + if (!ret) + { + error("error executing '%s': %s", cmd.c_str(), errString.c_str()); + return false; + } + res = outString; + return true; + } +}; + +/** + * Execute the "svn info" command and parse the result. + * This is a simple, small class. Define here, because it + * is used by MakeBase implementation methods. + */ +class SvnInfo : public MakeBase +{ +public: + +#if 0 + /** + * Safe way. Execute "svn info --xml" and parse the result. Search for + * elements/attributes. Safe from changes in format. + */ + bool query(const String &name, String &res) + { + String cmd = "svn info --xml"; + + String outString, errString; + bool ret = executeCommand(cmd.c_str(), "", outString, errString); + if (!ret) + { + error("error executing '%s': %s", cmd.c_str(), errString.c_str()); + return false; + } + Parser parser; + Element *elem = parser.parse(outString); + if (!elem) + { + error("error parsing 'svn info' xml result: %s", outString.c_str()); + return false; + } + + res = elem->getTagValue(name); + if (res.size()==0) + { + res = elem->getTagAttribute("entry", name); + } + return true; + } +#else + + + /** + * Universal way. Parse the file directly. Not so safe from + * changes in format. + */ + bool query(const String &name, String &res) + { + String fileName = resolve(".svn/entries"); + String nFileName = getNativePath(fileName); + + std::map properties; + + FILE *f = fopen(nFileName.c_str(), "r"); + if (!f) + { + error("could not open SVN 'entries' file"); + return false; + } + + const char *fieldNames[] = + { + "format-nbr", + "name", + "kind", + "revision", + "url", + "repos", + "schedule", + "text-time", + "checksum", + "committed-date", + "committed-rev", + "last-author", + "has-props", + "has-prop-mods", + "cachable-props", + }; + + for (int i=0 ; i<15 ; i++) + { + inbuf[0] = '\0'; + if (feof(f) || !fgets(inbuf, 255, f)) + break; + properties[fieldNames[i]] = trim(inbuf); + } + fclose(f); + + res = properties[name]; + + return true; + } + +private: + + char inbuf[256]; + +#endif + +}; + + + @@ -3551,14 +3796,31 @@ void MakeBase::error(const char *fmt, ...) void MakeBase::status(const char *fmt, ...) { va_list args; - va_start(args,fmt); //fprintf(stdout, " "); + va_start(args,fmt); vfprintf(stdout, fmt, args); + va_end(args); fprintf(stdout, "\n"); + fflush(stdout); +} + + +/** + * Print a printf()-like formatted trace message + */ +void MakeBase::trace(const char *fmt, ...) +{ + va_list args; + fprintf(stdout, "Make: "); + va_start(args,fmt); + vfprintf(stdout, fmt, args); va_end(args) ; + fprintf(stdout, "\n"); + fflush(stdout); } + /** * Resolve another path relative to this one */ @@ -3571,20 +3833,6 @@ String MakeBase::resolve(const String &otherPath) } -/** - * Print a printf()-like formatted trace message - */ -void MakeBase::trace(const char *fmt, ...) -{ - va_list args; - va_start(args,fmt); - fprintf(stdout, "Make: "); - vfprintf(stdout, fmt, args); - fprintf(stdout, "\n"); - va_end(args) ; -} - - /** * Check if a given string matches a given regex pattern @@ -3861,6 +4109,9 @@ static String win32LastError() + +#ifdef __WIN32__ + /** * Execute a system call, using pipes to send data to the * program's stdin, and reading stdout and stderr. @@ -3877,7 +4128,6 @@ bool MakeBase::executeCommand(const String &command, outbuf.clear(); errbuf.clear(); -#ifdef __WIN32__ /* I really hate having win32 code in this program, but the @@ -3921,13 +4171,18 @@ bool MakeBase::executeCommand(const String &command, return false; } SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0); - if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0)) - { - error("executeProgram: could not create pipe"); - delete[] paramBuf; - return false; - } - SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0); + if (&outbuf != &errbuf) { + if (!CreatePipe(&stderrRead, &stderrWrite, &saAttr, 0)) + { + error("executeProgram: could not create pipe"); + delete[] paramBuf; + return false; + } + SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0); + } else { + stderrRead = stdoutRead; + stderrWrite = stdoutWrite; + } // Create the process STARTUPINFO siStartupInfo; @@ -3969,7 +4224,7 @@ bool MakeBase::executeCommand(const String &command, error("executeCommand: could not close read pipe"); return false; } - if (!CloseHandle(stderrWrite)) + if (stdoutWrite != stderrWrite && !CloseHandle(stderrWrite)) { error("executeCommand: could not close read pipe"); return false; @@ -4027,7 +4282,7 @@ bool MakeBase::executeCommand(const String &command, error("executeCommand: could not close read pipe"); return false; } - if (!CloseHandle(stderrRead)) + if (stdoutRead != stderrRead && !CloseHandle(stderrRead)) { error("executeCommand: could not close read pipe"); return false; @@ -4046,35 +4301,136 @@ bool MakeBase::executeCommand(const String &command, return ret; -#else //do it unix-style +} + +#else /*do it unix style*/ + +#include + + - String s; - FILE *f = popen(command.c_str(), "r"); - int errnum = 0; - if (f) +/** + * Execute a system call, using pipes to send data to the + * program's stdin, and reading stdout and stderr. + */ +bool MakeBase::executeCommand(const String &command, + const String &inbuf, + String &outbuf, + String &errbuf) +{ + + status("============ cmd ============\n%s\n=============================", + command.c_str()); + + outbuf.clear(); + errbuf.clear(); + + + int outfds[2]; + if (pipe(outfds) < 0) + return false; + int errfds[2]; + if (pipe(errfds) < 0) + return false; + int pid = fork(); + if (pid < 0) + { + close(outfds[0]); + close(outfds[1]); + close(errfds[0]); + close(errfds[1]); + error("launch of command '%s' failed : %s", + command.c_str(), strerror(errno)); + return false; + } + else if (pid > 0) // parent + { + close(outfds[1]); + close(errfds[1]); + } + else // == 0, child + { + close(outfds[0]); + dup2(outfds[1], STDOUT_FILENO); + close(outfds[1]); + close(errfds[0]); + dup2(errfds[1], STDERR_FILENO); + close(errfds[1]); + + char *args[4]; + args[0] = (char *)"sh"; + args[1] = (char *)"-c"; + args[2] = (char *)command.c_str(); + args[3] = NULL; + execv("/bin/sh", args); + exit(EXIT_FAILURE); + } + + String outb; + String errb; + + int outRead = outfds[0]; + int errRead = errfds[0]; + int max = outRead; + if (errRead > max) + max = errRead; + + bool outOpen = true; + bool errOpen = true; + + while (outOpen || errOpen) { - while (true) + char ch; + fd_set fdset; + FD_ZERO(&fdset); + if (outOpen) + FD_SET(outRead, &fdset); + if (errOpen) + FD_SET(errRead, &fdset); + int ret = select(max+1, &fdset, NULL, NULL, NULL); + if (ret < 0) + break; + if (FD_ISSET(outRead, &fdset)) { - int ch = fgetc(f); - if (ch < 0) - break; - s.push_back((char)ch); + if (read(outRead, &ch, 1) <= 0) + { outOpen = false; } + else if (ch <= 0) + { /* outOpen = false; */ } + else + { outb.push_back(ch); } + } + if (FD_ISSET(errRead, &fdset)) + { + if (read(errRead, &ch, 1) <= 0) + { errOpen = false; } + else if (ch <= 0) + { /* errOpen = false; */ } + else + { errb.push_back(ch); } } - errnum = pclose(f); } - outbuf = s; - if (errnum != 0) + + int childReturnValue; + wait(&childReturnValue); + + close(outRead); + close(errRead); + + outbuf = outb; + errbuf = errb; + + if (childReturnValue != 0) { error("exec of command '%s' failed : %s", - command.c_str(), strerror(errno)); + command.c_str(), strerror(childReturnValue)); return false; } - else - return true; -#endif + return true; } +#endif + @@ -4086,7 +4442,7 @@ bool MakeBase::listDirectories(const String &baseName, String fullPath = baseName; if (dirName.size()>0) { - fullPath.append("/"); + if (dirName[0]!='/') fullPath.append("/"); fullPath.append(dirName); } DIR *dir = opendir(fullPath.c_str()); @@ -4109,7 +4465,7 @@ bool MakeBase::listDirectories(const String &baseName, fullChildPath.append(childName); struct stat finfo; String childNative = getNativePath(fullChildPath); - if (stat(childNative.c_str(), &finfo)<0) + if (cachedStat(childNative, &finfo)<0) { error("cannot stat file:%s", childNative.c_str()); } @@ -4278,7 +4634,7 @@ bool MakeBase::pkgConfigRecursive(const String packageName, if (path.size() > 0) pkgConfig.setPath(path); if (prefix.size() > 0) - pkgConfig.setPrefix(prefix); + pkgConfig.setPrefix(prefix); if (!pkgConfig.query(packageName)) return false; if (query == 0) @@ -4368,6 +4724,23 @@ bool MakeBase::lookupProperty(const String &propertyName, String &result) return false; result = val; } + else if (bzrPrefix.size() > 0 && + varname.compare(0, bzrPrefix.size(), bzrPrefix) == 0) + { + varname = varname.substr(bzrPrefix.size()); + String val; + //SvnInfo svnInfo; + BzrRevno bzrRevno; + if (varname == "revision") + { + if (!bzrRevno.query(val)) + return ""; + result = "r"+val; + } + /*if (!svnInfo.query(varname, val)) + return false; + result = val;*/ + } else { std::map::iterator iter; @@ -4390,16 +4763,17 @@ bool MakeBase::lookupProperty(const String &propertyName, String &result) /** * Analyse a string, looking for any substitutions or other - * things that need resilution + * things that need resolution */ bool MakeBase::getSubstitutionsRecursive(const String &str, String &result, int depth) { - if (depth > 4) + if (depth > 10) { - error("getSubstitutions: nesting of substitutions too deep"); + error("nesting of substitutions too deep (>10) for '%s'", + str.c_str()); return false; - } + } String s = trim(str); int len = (int)s.size(); String val; @@ -4485,10 +4859,12 @@ bool MakeBase::evalBool(const String &s, bool defaultVal) if (s.size()==0) return defaultVal; String val = eval(s, "false"); - if (s == "true" || s == "TRUE") + if (val.size()==0) + return defaultVal; + if (val == "true" || val == "TRUE") return true; else - return defaultVal; + return false; } @@ -4696,7 +5072,7 @@ bool MakeBase::createDirectory(const String &dirname) if (strlen(cnative)==2 && cnative[1]==':') return true; #endif - if (stat(cnative, &finfo)==0) + if (cachedStat(nativeDir, &finfo)==0) { if (!S_ISDIR(finfo.st_mode)) { @@ -4732,6 +5108,8 @@ bool MakeBase::createDirectory(const String &dirname) cnative, strerror(errno)); return false; } + + removeFromStatCache(nativeDir); return true; } @@ -4775,7 +5153,7 @@ bool MakeBase::removeDirectory(const String &dirName) struct stat finfo; String childNative = getNativePath(childName); char *cnative = (char *)childNative.c_str(); - if (stat(cnative, &finfo)<0) + if (cachedStat(childNative, &finfo)<0) { error("cannot stat file:%s", cnative); } @@ -4794,10 +5172,8 @@ bool MakeBase::removeDirectory(const String &dirName) else { //trace("DEL file: %s", childName.c_str()); - if (remove(cnative)<0) + if (!removeFile(childName)) { - error("error deleting %s : %s", - cnative, strerror(errno)); return false; } } @@ -4813,6 +5189,8 @@ bool MakeBase::removeDirectory(const String &dirName) return false; } + removeFromStatCache(native); + return true; } @@ -4826,7 +5204,7 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) //# 1 Check up-to-date times String srcNative = getNativePath(srcFile); struct stat srcinfo; - if (stat(srcNative.c_str(), &srcinfo)<0) + if (cachedStat(srcNative, &srcinfo)<0) { error("source file %s for copy does not exist", srcNative.c_str()); @@ -4835,7 +5213,7 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) String destNative = getNativePath(destFile); struct stat destinfo; - if (stat(destNative.c_str(), &destinfo)==0) + if (cachedStat(destNative, &destinfo)==0) { if (destinfo.st_mtime >= srcinfo.st_mtime) return true; @@ -4862,6 +5240,7 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) FILE *destf = fopen(destNative.c_str(), "wb"); if (!destf) { + fclose(srcf); error("copyFile cannot open %s for writing", srcNative.c_str()); return false; } @@ -4888,11 +5267,91 @@ bool MakeBase::copyFile(const String &srcFile, const String &destFile) #endif /* __WIN32__ */ + removeFromStatCache(destNative); + + return true; +} + + +/** + * Delete a file + */ +bool MakeBase::removeFile(const String &file) +{ + String native = getNativePath(file); + + if (!fileExists(native)) + { + return true; + } + +#ifdef WIN32 + // On Windows 'remove' will only delete files + + if (remove(native.c_str())<0) + { + if (errno==EACCES) + { + error("File %s is read-only", native.c_str()); + } + else if (errno==ENOENT) + { + error("File %s does not exist or is a directory", native.c_str()); + } + else + { + error("Failed to delete file %s: %s", native.c_str(), strerror(errno)); + } + return false; + } + +#else + + if (!isRegularFile(native)) + { + error("File %s does not exist or is not a regular file", native.c_str()); + return false; + } + + if (remove(native.c_str())<0) + { + if (errno==EACCES) + { + error("File %s is read-only", native.c_str()); + } + else + { + error( + errno==EACCES ? "File %s is read-only" : + errno==ENOENT ? "File %s does not exist or is a directory" : + "Failed to delete file %s: %s", native.c_str()); + } + return false; + } + +#endif + + removeFromStatCache(native); return true; } +/** + * Tests if the file exists + */ +bool MakeBase::fileExists(const String &fileName) +{ + String native = getNativePath(fileName); + struct stat finfo; + + //Exists? + if (cachedStat(native, &finfo)<0) + return false; + + return true; +} + /** * Tests if the file exists and is a regular file @@ -4903,7 +5362,7 @@ bool MakeBase::isRegularFile(const String &fileName) struct stat finfo; //Exists? - if (stat(native.c_str(), &finfo)<0) + if (cachedStat(native, &finfo)<0) return false; @@ -4923,7 +5382,7 @@ bool MakeBase::isDirectory(const String &fileName) struct stat finfo; //Exists? - if (stat(native.c_str(), &finfo)<0) + if (cachedStat(native, &finfo)<0) return false; @@ -4945,7 +5404,7 @@ bool MakeBase::isNewerThan(const String &fileA, const String &fileB) String nativeA = getNativePath(fileA); struct stat infoA; //IF source does not exist, NOT newer - if (stat(nativeA.c_str(), &infoA)<0) + if (cachedStat(nativeA, &infoA)<0) { return false; } @@ -4953,7 +5412,7 @@ bool MakeBase::isNewerThan(const String &fileA, const String &fileB) String nativeB = getNativePath(fileB); struct stat infoB; //IF dest does not exist, YES, newer - if (stat(nativeB.c_str(), &infoB)<0) + if (cachedStat(nativeB, &infoB)<0) { return true; } @@ -5296,15 +5755,16 @@ bool PkgConfig::query(const String &pkgName) fname.append(".pc"); if (!readFile(fname)) + { + error("Cannot find package '%s'. Do you have it installed?", + pkgName.c_str()); return false; + } return true; } - - - //######################################################################## //# D E P T O O L //######################################################################## @@ -6259,6 +6719,9 @@ public: TASK_NONE, TASK_CC, TASK_COPY, + TASK_CXXTEST_PART, + TASK_CXXTEST_ROOT, + TASK_CXXTEST_RUN, TASK_DELETE, TASK_ECHO, TASK_JAR, @@ -6635,6 +7098,8 @@ public: } if (errorOccurred && !continueOnError) break; + + removeFromStatCache(getNativePath(destFullName)); } if (f) @@ -6763,8 +7228,9 @@ public: fileName.c_str(), toFileName.c_str()); String fullSource = parent.resolve(fileName); String fullDest = parent.resolve(toFileName); - //trace("copy %s to file %s", fullSource.c_str(), - // fullDest.c_str()); + if (verbose) + taskstatus("copy %s to file %s", fullSource.c_str(), + fullDest.c_str()); if (!isRegularFile(fullSource)) { error("copy : file %s does not exist", fullSource.c_str()); @@ -6829,11 +7295,13 @@ public: destPath.append(fileName); String fullDest = parent.resolve(destPath); //trace("fileName:%s", fileName.c_str()); - //trace("copy %s to new dir : %s", fullSource.c_str(), - // fullDest.c_str()); + if (verbose) + taskstatus("copy %s to new dir : %s", + fullSource.c_str(), fullDest.c_str()); if (!isNewerThan(fullSource, fullDest)) { - //trace("copy skipping %s", fullSource.c_str()); + if (verbose) + taskstatus("copy skipping %s", fullSource.c_str()); continue; } if (!copyFile(fullSource, fullDest)) @@ -6861,8 +7329,9 @@ public: } destPath.append(baseName); String fullDest = parent.resolve(destPath); - //trace("copy %s to new dir : %s", fullSource.c_str(), - // fullDest.c_str()); + if (verbose) + taskstatus("file %s to new dir : %s", fullSource.c_str(), + fullDest.c_str()); if (!isRegularFile(fullSource)) { error("copy : file %s does not exist", fullSource.c_str()); @@ -6960,6 +7429,301 @@ private: }; +/** + * Generate CxxTest files + */ +class TaskCxxTestPart: public Task +{ +public: + + TaskCxxTestPart(MakeBase &par) : Task(par) + { + type = TASK_CXXTEST_PART; + name = "cxxtestpart"; + } + + virtual ~TaskCxxTestPart() + {} + + virtual bool execute() + { + if (!listFiles(parent, fileSet)) + return false; + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); + + String fullDest = parent.resolve(parent.eval(destPathOpt, ".")); + String cmd = parent.eval(commandOpt, "cxxtestgen.py"); + cmd.append(" --part -o "); + cmd.append(fullDest); + + unsigned int newFiles = 0; + for (unsigned int i=0 ; i0) + { + sourcePath.append(fileSetDir); + sourcePath.append("/"); + } + sourcePath.append(fileName); + String fullSource = parent.resolve(sourcePath); + + cmd.append(" "); + cmd.append(fullSource); + if (isNewerThan(fullSource, fullDest)) newFiles++; + } + + if (newFiles>0) { + size_t const lastSlash = fullDest.find_last_of('/'); + if (lastSlash != fullDest.npos) { + String directory(fullDest, 0, lastSlash); + if (!createDirectory(directory)) + return false; + } + + String outString, errString; + if (!executeCommand(cmd.c_str(), "", outString, errString)) + { + error(" problem: %s", errString.c_str()); + return false; + } + removeFromStatCache(getNativePath(fullDest)); + } + + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "out", destPathOpt)) + return false; + + std::vector children = elem->getChildren(); + for (unsigned int i=0 ; igetName(); + if (tagName == "fileset") + { + if (!parseFileSet(child, parent, fileSet)) + return false; + } + } + return true; + } + +private: + + String commandOpt; + String destPathOpt; + FileSet fileSet; + +}; + + +/** + * Generate the CxxTest root file + */ +class TaskCxxTestRoot: public Task +{ +public: + + TaskCxxTestRoot(MakeBase &par) : Task(par) + { + type = TASK_CXXTEST_ROOT; + name = "cxxtestroot"; + } + + virtual ~TaskCxxTestRoot() + {} + + virtual bool execute() + { + if (!listFiles(parent, fileSet)) + return false; + String fileSetDir = parent.eval(fileSet.getDirectory(), "."); + unsigned int newFiles = 0; + + String fullDest = parent.resolve(parent.eval(destPathOpt, ".")); + String cmd = parent.eval(commandOpt, "cxxtestgen.py"); + cmd.append(" --root -o "); + cmd.append(fullDest); + String templateFile = parent.eval(templateFileOpt, ""); + if (templateFile.size()>0) { + String fullTemplate = parent.resolve(templateFile); + cmd.append(" --template="); + cmd.append(fullTemplate); + if (isNewerThan(fullTemplate, fullDest)) newFiles++; + } + + for (unsigned int i=0 ; i0) + { + sourcePath.append(fileSetDir); + sourcePath.append("/"); + } + sourcePath.append(fileName); + String fullSource = parent.resolve(sourcePath); + + cmd.append(" "); + cmd.append(fullSource); + if (isNewerThan(fullSource, fullDest)) newFiles++; + } + + if (newFiles>0) { + size_t const lastSlash = fullDest.find_last_of('/'); + if (lastSlash != fullDest.npos) { + String directory(fullDest, 0, lastSlash); + if (!createDirectory(directory)) + return false; + } + + String outString, errString; + if (!executeCommand(cmd.c_str(), "", outString, errString)) + { + error(" problem: %s", errString.c_str()); + return false; + } + removeFromStatCache(getNativePath(fullDest)); + } + + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "template", templateFileOpt)) + return false; + if (!parent.getAttribute(elem, "out", destPathOpt)) + return false; + + std::vector children = elem->getChildren(); + for (unsigned int i=0 ; igetName(); + if (tagName == "fileset") + { + if (!parseFileSet(child, parent, fileSet)) + return false; + } + } + return true; + } + +private: + + String commandOpt; + String templateFileOpt; + String destPathOpt; + FileSet fileSet; + +}; + + +/** + * Execute the CxxTest test executable + */ +class TaskCxxTestRun: public Task +{ +public: + + TaskCxxTestRun(MakeBase &par) : Task(par) + { + type = TASK_CXXTEST_RUN; + name = "cxxtestrun"; + } + + virtual ~TaskCxxTestRun() + {} + + virtual bool execute() + { + unsigned int newFiles = 0; + + String workingDir = parent.resolve(parent.eval(workingDirOpt, "inkscape")); + String rawCmd = parent.eval(commandOpt, "build/cxxtests"); + + String cmdExe; + if (fileExists(rawCmd)) { + cmdExe = rawCmd; + } else if (fileExists(rawCmd + ".exe")) { + cmdExe = rawCmd + ".exe"; + } else { + error(" problem: cxxtests executable not found! (command=\"%s\")", rawCmd.c_str()); + } + // Note that the log file names are based on the exact name used to call cxxtests (it uses argv[0] + ".log"/".xml") + if (isNewerThan(cmdExe, rawCmd + ".log") || isNewerThan(cmdExe, rawCmd + ".xml")) newFiles++; + + // Prepend the necessary ../'s + String cmd = rawCmd; + unsigned int workingDirDepth = 0; + bool wasSlash = true; + for(size_t i=0; i0) { + char olddir[1024]; + if (workingDir.size()>0) { + // TODO: Double-check usage of getcwd and handle chdir errors + getcwd(olddir, 1024); + chdir(workingDir.c_str()); + } + + String outString; + if (!executeCommand(cmd.c_str(), "", outString, outString)) + { + error(" problem: %s", outString.c_str()); + return false; + } + + if (workingDir.size()>0) { + // TODO: Handle errors? + chdir(olddir); + } + + removeFromStatCache(getNativePath(cmd + ".log")); + removeFromStatCache(getNativePath(cmd + ".xml")); + } + + return true; + } + + virtual bool parse(Element *elem) + { + if (!parent.getAttribute(elem, "command", commandOpt)) + return false; + if (!parent.getAttribute(elem, "workingdir", workingDirOpt)) + return false; + return true; + } + +private: + + String commandOpt; + String workingDirOpt; + +}; + + /** * */ @@ -6991,37 +7755,33 @@ public: bool verbose = parent.evalBool(verboseOpt, false); bool quiet = parent.evalBool(quietOpt, false); bool failOnError = parent.evalBool(failOnErrorOpt, true); - struct stat finfo; switch (delType) { case DEL_FILE: { - status(" : %s", fileName.c_str()); + taskstatus("file: %s", fileName.c_str()); String fullName = parent.resolve(fileName); char *fname = (char *)fullName.c_str(); - //does not exist - if (stat(fname, &finfo)<0) - return true; - //exists but is not a regular file - if (!S_ISREG(finfo.st_mode)) - { - error(" failed. '%s' exists and is not a regular file", - fname); - return false; - } - if (remove(fname)<0) + if (!quiet && verbose) + taskstatus("path: %s", fname); + if (failOnError && !removeFile(fullName)) { - error(" failed: %s", strerror(errno)); + //error("Could not delete file '%s'", fullName.c_str()); return false; } return true; } case DEL_DIR: { - taskstatus("%s", dirName.c_str()); + taskstatus("dir: %s", dirName.c_str()); String fullDir = parent.resolve(dirName); - if (!removeDirectory(fullDir)) + if (!quiet && verbose) + taskstatus("path: %s", fullDir.c_str()); + if (failOnError && !removeDirectory(fullDir)) + { + //error("Could not delete directory '%s'", fullDir.c_str()); return false; + } return true; } } @@ -7151,6 +7911,7 @@ public: execCmd.c_str(), errString.c_str()); return false; } + removeFromStatCache(getNativePath(destfile)); return true; } @@ -7268,6 +8029,8 @@ public: execCmd.c_str(), errString.c_str()); return false; } + // TODO: + //removeFromStatCache(getNativePath(........)); return true; } @@ -7370,6 +8133,7 @@ public: error("LINK problem: %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(fullTarget)); if (symFileName.size()>0) { @@ -7384,6 +8148,7 @@ public: error(" symbol file failed : %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(symFullName)); } if (doStrip) @@ -7396,6 +8161,7 @@ public: error(" failed : %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(fullTarget)); } return true; @@ -7475,13 +8241,14 @@ public: virtual bool execute() { String fileName = parent.eval(fileNameOpt, ""); + bool force = parent.evalBool(forceOpt, false); String text = parent.eval(textOpt, ""); taskstatus("%s", fileName.c_str()); String fullName = parent.resolve(fileName); - if (!isNewerThan(parent.getURI().getPath(), fullName)) + if (!force && !isNewerThan(parent.getURI().getPath(), fullName)) { - //trace("skipped "); + taskstatus("skipped"); return true; } String fullNative = getNativePath(fullName); @@ -7497,6 +8264,7 @@ public: fputc(text[i], f); fputc('\n', f); fclose(f); + removeFromStatCache(fullNative); return true; } @@ -7504,6 +8272,8 @@ public: { if (!parent.getAttribute(elem, "file", fileNameOpt)) return false; + if (!parent.getAttribute(elem, "force", forceOpt)) + return false; if (fileNameOpt.size() == 0) { error(" requires 'file=\"filename\"' attribute"); @@ -7519,6 +8289,7 @@ public: private: String fileNameOpt; + String forceOpt; String textOpt; }; @@ -7663,6 +8434,7 @@ public: error(" problem: %s", errString.c_str()); return false; } + removeFromStatCache(getNativePath(fullDest)); } return true; @@ -7837,6 +8609,8 @@ public: String outbuf, errbuf; if (!executeCommand(cmd, "", outbuf, errbuf)) return false; + // TODO: + //removeFromStatCache(getNativePath(fullDest)); return true; } @@ -7900,6 +8674,7 @@ public: error("RC problem: %s", errString.c_str()); return false; } + removeFromStatCache(getNativePath(fullOut)); return true; } @@ -8025,7 +8800,7 @@ public: error(" problem: %s", errString.c_str()); return false; } - + removeFromStatCache(getNativePath(fullOut)); return true; } @@ -8146,7 +8921,7 @@ public: error(" problem: %s", errString.c_str()); return false; } - + removeFromStatCache(getNativePath(fullOut)); return true; } @@ -8229,6 +9004,7 @@ public: error(" failed : %s", errbuf.c_str()); return false; } + removeFromStatCache(getNativePath(fullName)); return true; } @@ -8294,6 +9070,7 @@ public: nativeFile.c_str(), strerror(ret)); return false; } + removeFromStatCache(nativeFile); return true; } @@ -8353,6 +9130,12 @@ Task *Task::createTask(Element *elem, int lineNr) task = new TaskCC(parent); else if (tagName == "copy") task = new TaskCopy(parent); + else if (tagName == "cxxtestpart") + task = new TaskCxxTestPart(parent); + else if (tagName == "cxxtestroot") + task = new TaskCxxTestRoot(parent); + else if (tagName == "cxxtestrun") + task = new TaskCxxTestRun(parent); else if (tagName == "delete") task = new TaskDelete(parent); else if (tagName == "echo") @@ -8747,6 +9530,7 @@ void Make::init() pcPrefix = "pc."; pccPrefix = "pcc."; pclPrefix = "pcl."; + bzrPrefix = "bzr."; properties.clear(); for (unsigned int i = 0 ; i < allTasks.size() ; i++) delete allTasks[i]; @@ -9165,6 +9949,16 @@ bool Make::parseProperty(Element *elem) pclPrefix = attrVal; pclPrefix.push_back('.'); } + else if (attrName == "subversion") + { + if (attrVal.find('.') != attrVal.npos) + { + error("bzr prefix cannot have a '.' in it"); + return false; + } + bzrPrefix = attrVal; + bzrPrefix.push_back('.'); + } } return true;