Hi,
This patch adds a dependence tracking mechanism to postinstall scripts.
The idea is essentially the one described in
<http://cygwin.com/ml/cygwin-apps/2003-03/msg00022.html>. This patch is
very preliminary, and not tested much beyond its ability to sort scripts
correctly (compiles, though). This should provide a foundation for
further refinement, however. Please comment.
Igor
==============================================================================
ChangeLog:
2003-03-03 Igor Pechtchanski <[EMAIL PROTECTED]>
* postinstall.cc (RunFindVisitor::executeAll): New
member function that propagates script dependences,
topologically sorts the script list, and then executes
the scripts.
(RunFindVisitor::visitFile): Add file to list instead of
running it.
(RunFindVisitor::files): New member variable.
(processFile): New static helper function that extracts
dependences from each script file.
(do_postinstall): Add executeAll call.
(FileDesc): New helper class.
(sharpbang): New static helper function.
--
http://cs.nyu.edu/~pechtcha/
|\ _,,,---,,_ [EMAIL PROTECTED]
ZZZzz /,`.-'`' -. ;-;;,_ [EMAIL PROTECTED]
|,4- ) )-,_. ,\ ( `'-' Igor Pechtchanski
'---''(_/--' `-'\_) fL a.k.a JaguaR-R-R-r-r-r-.-.-. Meow!
Oh, boy, virtual memory! Now I'm gonna make myself a really *big* RAMdisk!
-- /usr/games/fortune
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 04:29:26 -0000
@@ -26,6 +26,112 @@ 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 <list>
+#include <set>
+#include <map>
+
+struct FileDesc
+{
+ String path;
+ std::set<FileDesc*> dependences;
+ bool mark;
+ static std::map<String, FileDesc*, String::caseless> fdmap;
+
+ FileDesc(String const &basePath) : path(basePath), mark(false) { }
+ bool addDependence(FileDesc *dep) {
+ return dependences.insert(dep).second;
+ }
+ bool addDependence(String const &deps) {
+ return addDependence(create(deps));
+ }
+ void propagateDependences() {
+ // TODO: detect circular dependences
+ if (mark) return;
+ mark = true;
+ for (std::set<FileDesc*>::iterator i = dependences.begin();
+ i != dependences.end();
+ ++i)
+ {
+ (*i)->propagateDependences();
+ for (std::set<FileDesc*>::iterator d = (*i)->dependences.begin();
+ d != (*i)->dependences.end();
+ ++d)
+ addDependence(*d);
+ }
+ }
+ static FileDesc *create(String const &path) {
+ FileDesc *&fd = fdmap[path];
+ if (fd == NULL) fd = new FileDesc(path);
+ return fd;
+ }
+ 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);
+ }
+};
+std::map<String, FileDesc*, String::caseless> FileDesc::fdmap;
+
+#define WHITESPACE " \t"
+
+inline bool sharpbang(char *line)
+{
+ if (*line != '#') return false;
+ char *bang = strtok(line+1, WHITESPACE);
+ return (bang != NULL && *bang == '!');
+}
+
+#define DEPEND_STR "depends on: "
+
+static FileDesc *processFile(String const &basePath)
+{
+ // TODO: free unused map entries
+ FileDesc *retval = FileDesc::create(basePath);
+ char const *ext = strrchr (basePath.cstr_oneuse(), '.');
+ char const *cmt = NULL;
+ if (strcasecmp(ext, ".sh") == 0)
+ cmt = "#";
+ else if (strcasecmp(ext, ".bat") == 0)
+ cmt = "rem";
+ // Open file
+ io_stream *f = io_stream::open(String("file://") + basePath, "rt");
+ if (!f)
+ {
+ const char *err = strerror (errno);
+ if (!err)
+ err = "(unknown error)";
+ note (NULL, IDS_ERR_OPEN_READ, basePath.cstr_oneuse(), err);
+ return retval;
+ }
+
+ // Read first available line
+ char line[500];
+ f->gets(line, 500);
+ if (sharpbang(line))
+ f->gets(line, 500);
+
+ // Parse dependences
+ if (strncasecmp(line, cmt, strlen(cmt)) == 0)
+ {
+ char *dstr = strtok(line+strlen(cmt), WHITESPACE);
+ if (strncasecmp(dstr, DEPEND_STR, strlen(DEPEND_STR)) == 0)
+ {
+ // for each dependence
+ while ((dstr = strtok(NULL, WHITESPACE)) != NULL)
+ retval->addDependence(dstr);
+ }
+ }
+ delete f;
+ return retval;
+}
class RunFindVisitor : public FindVisitor
{
@@ -33,14 +139,49 @@ public:
RunFindVisitor (){}
virtual void visitFile(String const &basePath, const WIN32_FIND_DATA *theFile)
{
- run_script ("/etc/postinstall/", theFile->cFileName);
+ files.push_back(processFile(basePath));
}
- virtual ~ RunFindVisitor () {}
+ virtual ~ RunFindVisitor ();
+ virtual void executeAll ();
protected:
RunFindVisitor (RunFindVisitor const &);
RunFindVisitor & operator= (RunFindVisitor const &);
+private:
+ std::list<FileDesc*> files;
};
+RunFindVisitor::~RunFindVisitor()
+{
+ for (std::list<FileDesc*>::iterator i = files.begin(); i != files.end(); ++i)
+ delete *i;
+}
+
+inline bool lt_fd(FileDesc *f1, FileDesc *f2) { return (*f1) < (*f2); }
+
+void RunFindVisitor::executeAll()
+{
+ for (std::list<FileDesc*>::iterator i = files.begin(); i != files.end(); ++i)
+ (*i)->propagateDependences();
+ // Topological sort
+ files.sort(lt_fd);
+ for (std::list<FileDesc*>::iterator i = files.begin(); i != files.end(); ++i)
+ {
+ // Check that all dependences are executed already
+ for (std::set<FileDesc*>::iterator d = (*i)->dependences.begin();
+ d != (*i)->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 " + (*i)->path);
+ }
+ run_script ("/etc/postinstall/", (*i)->path);
+ }
+}
+
void
do_postinstall (HINSTANCE h, HWND owner)
{
@@ -50,4 +191,5 @@ do_postinstall (HINSTANCE h, HWND owner)
RunFindVisitor myVisitor;
String postinst = cygpath ("/etc/postinstall");
Find (postinst).accept (myVisitor);
+ myVisitor.executeAll();
}