Index: postinstall.cc =================================================================== RCS file: /cvs/cygwin-apps/setup/postinstall.cc,v retrieving revision 2.9 diff -u -p -r2.9 postinstall.cc --- postinstall.cc 19 May 2002 03:07:51 -0000 2.9 +++ postinstall.cc 4 Mar 2003 17:54:20 -0000 @@ -26,6 +26,140 @@ static const char *cvsid = #include "mount.h" #include "script.h" #include "FindVisitor.h" +#include "io_stream.h" +#include "resource.h" +#include "msg.h" +#include "log.h" +#include +#include +#include + +#define DEPEND_STR "depends on: " +#define BUFLEN 500 + +class FileDesc +{ +public: + FileDesc(String const &basePath); + String const &path() { return _path; } + std::set const & dependences() { return _dependences; } + bool addDependence(FileDesc *dep) { + return _dependences.insert(dep).second; + } + bool addDependence(String const &deps) { + // TODO: free unused map entries + return addDependence(create(deps)); + } + void propagateDependences() { + // TODO: detect circular dependences + if (_mark) return; + _mark = true; + for (std::set::iterator i = _dependences.begin(); + i != _dependences.end(); + ++i) + { + (*i)->propagateDependences(); + for (std::set::iterator d = (*i)->_dependences.begin(); + d != (*i)->_dependences.end(); + ++d) + addDependence(*d); + } + } + bool operator == (FileDesc const &f) const { + return _path == f._path && _dependences == f._dependences; + } + bool operator > (FileDesc &f) { + return (_dependences.find(&f) != _dependences.end()); + } + bool operator < (FileDesc &f) { + return (f > *this); + } + + static FileDesc *create(String const &path) { + FileDesc *&fd = fdmap[path]; + if (fd == NULL) fd = new FileDesc(path); + return fd; + } +private: + String _path; + std::set _dependences; + bool _mark; + char _buf[BUFLEN]; + char const *commentString(); + char *readDependenceLine(); + + static std::map fdmap; +}; + +char const *FileDesc::commentString() +{ + char const *ext = strrchr (_path.cstr_oneuse(), '.'); + char const *cmt = NULL; + if (strcasecmp(ext, ".sh") == 0) + cmt = "#"; + else if (strcasecmp(ext, ".bat") == 0) + cmt = "rem"; + return cmt; +} + +#define WHITESPACE " \t" + +char *FileDesc::readDependenceLine() +{ + io_stream *f = io_stream::open(String("file://") + _path, "rt"); + if (!f) + { + const char *err = strerror (errno); + if (!err) + err = "(unknown error)"; + note (NULL, IDS_ERR_OPEN_READ, _path.cstr_oneuse(), err); + return NULL; + } + + // Read first line after shbang (if any) + f->gets(_buf, BUFLEN); + if (*_buf == '#') + { + char *bang = strtok(_buf+1, WHITESPACE); + if (bang != NULL && *bang == '!') + f->gets(_buf, BUFLEN); + else + *(bang+strlen(bang)) = ' '; + } + + delete f; + + // Check if a dependence line + char const *cmt = commentString(); + + // - has to start with a comment + if (strncasecmp(_buf, cmt, strlen(cmt)) != 0) + return NULL; + // - has to contain a marker after whitespace + char *mstr = strtok(_buf+strlen(cmt), WHITESPACE); + if (mstr == NULL) + return NULL; + *(mstr+strlen(mstr)) = ' '; + if (strncasecmp(mstr, DEPEND_STR, strlen(DEPEND_STR)) != 0) + return NULL; + + return strchr(mstr, ':')+1; +} + +FileDesc::FileDesc(String const &basePath) : _path(basePath), _mark(false) +{ + char *line = readDependenceLine(); + if (line == NULL) // Unable to open file or no dependences + return; + + // Parse dependences + for (char *dstr = strtok(line, WHITESPACE); + dstr == NULL; + dstr = strtok(NULL, WHITESPACE)) + addDependence(dstr); // for each dependence +} + +std::map FileDesc::fdmap; class RunFindVisitor : public FindVisitor { @@ -33,14 +167,55 @@ public: RunFindVisitor (){} virtual void visitFile(String const &basePath, const WIN32_FIND_DATA *theFile) { - run_script ("/etc/postinstall/", theFile->cFileName); + files.push_back(FileDesc::create(basePath)); } - virtual ~ RunFindVisitor () {} + virtual ~ RunFindVisitor (); + virtual void executeAll (); protected: RunFindVisitor (RunFindVisitor const &); RunFindVisitor & operator= (RunFindVisitor const &); +private: + std::list files; + void checkAndLogMissingDependences(FileDesc *); }; +RunFindVisitor::~RunFindVisitor() +{ + for (std::list::iterator i = files.begin(); i != files.end(); ++i) + delete *i; +} + +inline bool lt_fd(FileDesc *f1, FileDesc *f2) { return (*f1) < (*f2); } + +void RunFindVisitor::checkAndLogMissingDependences(FileDesc *f) +{ + // Check that all dependences are executed already + for (std::set::iterator d = f->dependences().begin(); + d != f->dependences().end(); + ++d) + if (!io_stream::exists (String("file://") + (*d)->path() + ".done")) + { + char const *msg = "missing"; + if (!io_stream::exists (String("file://") + (*d)->path())) + msg = "not executed"; + log (LOG_TIMESTAMP, String("error: dependence ") + (*d)->path() + + " " + msg + " for script " + f->path()); + } +} + +void RunFindVisitor::executeAll() +{ + for (std::list::iterator i = files.begin(); i != files.end(); ++i) + (*i)->propagateDependences(); + // Topological sort + files.sort(lt_fd); + for (std::list::iterator i = files.begin(); i != files.end(); ++i) + { + checkAndLogMissingDependences(*i); + run_script ("/etc/postinstall/", (*i)->path()); + } +} + void do_postinstall (HINSTANCE h, HWND owner) { @@ -50,4 +225,5 @@ do_postinstall (HINSTANCE h, HWND owner) RunFindVisitor myVisitor; String postinst = cygpath ("/etc/postinstall"); Find (postinst).accept (myVisitor); + myVisitor.executeAll(); }