[PATCH] Run postinstall scripts in a thread with progress bars - take 3

Igor Pechtchanski pechtcha@cs.nyu.edu
Tue Mar 25 01:33:00 GMT 2003


On Mon, 24 Mar 2003, Igor Pechtchanski wrote:

> On 25 Mar 2003, Robert Collins wrote:
>
> > On Tue, 2003-03-25 at 11:00, Igor Pechtchanski wrote:
> > > > run_package_scripts cries our for a helper class IMO.
> > > >
> > > > i.e. ScriptRunner with
> > > > a) constructor
> > > > b) destructor
> > > > c) run(std::vector<Script> const &) method.
> > > > d) operator () (Script const &aScript) method.
> > >
> > > I don't see the benefit of run(); it'll be subsumed by operator(), IMO.
> > > Otherwise, I'll give it a shot.
> >
> > well, you'll have one instance of ScriptRunner for both the dependency
> > order package scripts, and the found-by-filename scripts. If you have
> > pre-running-a-vector or post-running-a-vector code, then that belongs in
> > run(). If that code goes into the constructor, then sure, eliminate
> > run().
>
> Yep, I think the pre-post vector code could go into the
> constructor/destructor.
>
> > > > this:
> > > > for (std::vector<Script>::iterator script = scripts.begin();
> > > > +       script != scripts.end();
> > > > +       ++script)
> > > >
> > > > then becomes
> > > > *this = for_each (scripts.begin(), scripts.end(), *this);
> > >
> > > We could probably just lose the return value...
> >
> > Check the template, IIRC it takes a copy of the object, calls the copy's
> > operator (), then returns a copy of the copy.
> > i.e. if we want failure stats, script run counts etc, we need the return
> > value.
> > Rob
>
> Yes, but we don't keep failure stats.  If we ever decide to, we can easily
> capture the return value later.  I'm pretty sure we can ignore it for now.
>
> Thanks for the feedback.  I'll send the next iteration soon.
>         Igor

...and here it is.  Attached.
	Igor
==============================================================================
ChangeLog:
2003-03-24  Igor Pechtchanski <pechtcha@cs.nyu.edu>

	* threebar.h (WM_APP_START_POSTINSTALL): New message.
	(WM_APP_POSTINSTALL_THREAD_COMPLETE): New message.
	* threebar.cc (ThreeBarProgressPage::OnMessageApp):
	Add handling for WM_APP_START_POSTINSTALL and
	WM_APP_POSTINSTALL_THREAD_COMPLETE.
	* install.cc (do_install_thread): Set next_dialog to
	IDD_S_POSTINSTALL.
	* desktop.cc (DesktopSetupPage::OnFinish): Move the
	do_postinstall call to ThreeBarProgressPage::OnMessageApp.
	* script.h (Script::fullName): New member function.
	(Script::run): New member function.
	(Script::ETCPostinstall): New static member constant.
	* script.cc (Script::fullName): Implement.
	(Script::run): Implement.
	(Script::ETCPostinstall): Define.
	(Script::isAScript): Use ETCPostinstall instead of a
	hardcoded string constant.
	(run): Enable "#if 0"'d code.
	* postinstall.cc (Progress): New extern variable.
	(RunFindVisitor::visitFile): Add script to vector
	instead of running.
	(RunFindVisitor::_scripts): New member variable.
	(RunScript): New helper class for use in for_each.
	(do_postinstall_thread): Rename do_postinstall to.  Add
	Progress bar and text setting.  Add package count.
	(do_postinstall_reflector): New static function.
	(do_postinstall): Rename to do_postinstall_thread.
	Create a thread instead.

-- 
				http://cs.nyu.edu/~pechtcha/
      |\      _,,,---,,_		pechtcha@cs.nyu.edu
ZZZzz /,`.-'`'    -.  ;-;;,_		igor@watson.ibm.com
     |,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
-------------- next part --------------
Index: desktop.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/desktop.cc,v
retrieving revision 2.34
diff -u -p -r2.34 desktop.cc
--- desktop.cc	25 Nov 2002 22:12:08 -0000	2.34
+++ desktop.cc	25 Mar 2003 01:24:28 -0000
@@ -397,8 +397,6 @@ DesktopSetupPage::OnFinish ()
   HWND h = GetHWND ();
   save_dialog (h);
   do_desktop_setup ();
-  NEXT (IDD_S_POSTINSTALL);
-  do_postinstall (GetInstance (), h);
 
   return true;
 }
Index: install.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/install.cc,v
retrieving revision 2.60
diff -u -p -r2.60 install.cc
--- install.cc	17 Mar 2003 22:23:33 -0000	2.60
+++ install.cc	25 Mar 2003 01:24:28 -0000
@@ -455,7 +455,7 @@ do_install_thread (HINSTANCE h, HWND own
   num_installs = 0, num_uninstalls = 0, num_replacements = 0;
   rebootneeded = false;
 
-  next_dialog = IDD_DESKTOP;
+  next_dialog = IDD_S_POSTINSTALL;
 
   io_stream::mkpath_p (PATH_TO_DIR, String ("file://") + get_root_dir ());
 
Index: postinstall.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/postinstall.cc,v
retrieving revision 2.12
diff -u -p -r2.12 postinstall.cc
--- postinstall.cc	20 Mar 2003 10:02:51 -0000	2.12
+++ postinstall.cc	25 Mar 2003 01:24:28 -0000
@@ -29,40 +29,124 @@ static const char *cvsid =
 #include "FilterVisitor.h"
 #include "package_db.h"
 #include "package_meta.h"
+#include "resource.h"
+#include "threebar.h"
+
+#include <algorithm>
+
+using namespace std;
+
+extern ThreeBarProgressPage Progress;
 
 class RunFindVisitor : public FindVisitor
 {
 public:
-  RunFindVisitor (){}
+  RunFindVisitor (vector<Script> *scripts) : _scripts(scripts) {}
   virtual void visitFile(String const &basePath, const WIN32_FIND_DATA *theFile)
     {
-      run_script ("/etc/postinstall/", theFile->cFileName, TRUE);
+      String fn = String("/etc/postinstall/")+theFile->cFileName;
+      _scripts->push_back(Script (fn));
     }
   virtual ~ RunFindVisitor () {}
 protected:
   RunFindVisitor (RunFindVisitor const &);
   RunFindVisitor & operator= (RunFindVisitor const &);
+private:
+  vector<Script> *_scripts;
 };
-  
-void
-do_postinstall (HINSTANCE h, HWND owner)
+
+class RunScript : public unary_function<Script const &, void>
 {
-  next_dialog = 0;
+public:
+  RunScript(String const &name, int num) : _num(num), _cnt(0)
+    {
+      Progress.SetText2 (name.cstr_oneuse());
+      Progress.SetBar1 (_cnt, _num);
+    }
+  virtual ~RunScript()
+    {
+      Progress.SetText3 ("");
+    }
+  void operator() (Script const &aScript) 
+    {
+      Progress.SetText3 (aScript.fullName().cstr_oneuse());
+      aScript.run(TRUE);
+      ++_cnt;
+      Progress.SetBar1 (_cnt, _num);
+    }
+private:
+  int _num;
+  int _cnt;
+};
+
+static void
+do_postinstall_thread (HINSTANCE h, HWND owner)
+{
+  next_dialog = IDD_DESKTOP;
+
+  Progress.SetText1 ("Running...");
+  Progress.SetText2 ("");
+  Progress.SetText3 ("");
+  Progress.SetBar1 (0, 1);
+  Progress.SetBar2 (0, 1);
+
   init_run_script ();
   SetCurrentDirectory (get_root_dir ().cstr_oneuse());
   packagedb db;
+  vector<packagemeta*> packages;
   PackageDBConnectedIterator i = db.connectedBegin ();
   while (i != db.connectedEnd ())
     {
       packagemeta & pkg = **i;
       if (pkg.installed)
-	for (std::vector<Script>::iterator script=pkg.installed.scripts().begin(); script != pkg.installed.scripts().end(); ++script) 
-	  run_script ("/etc/postinstall/", script->baseName(), TRUE);
+	packages.push_back(&pkg);
       ++i;
     }
-  RunFindVisitor myVisitor;
+  int numpkg = packages.size() + 1;
+  int k = 0;
+  for (i = packages.begin (); i != packages.end (); ++i)
+    {
+      packagemeta & pkg = **i;
+      for_each (pkg.installed.scripts().begin(), pkg.installed.scripts().end(),
+		RunScript(pkg.name, pkg.installed.scripts().size()));
+      ++k;
+      Progress.SetBar2 (k, numpkg);
+    }
   ExcludeNameFilter notDone("*.done");
-  FilterVisitor excludeDoneVisitor(&myVisitor, &notDone);
   String postinst = cygpath ("/etc/postinstall");
+  vector<Script> scripts;
+  RunFindVisitor myVisitor (&scripts);
+  FilterVisitor excludeDoneVisitor(&myVisitor, &notDone);
+  Progress.SetBar1 (0, 1);
   Find (postinst).accept (excludeDoneVisitor);
+  for_each (scripts.begin(), scripts.end(),
+	    RunScript("No package", scripts.size()));
+  Progress.SetBar2 (numpkg, numpkg);
+}
+
+static DWORD WINAPI
+do_postinstall_reflector (void *p)
+{
+  HANDLE *context;
+  context = (HANDLE *) p;
+
+  do_postinstall_thread ((HINSTANCE) context[0], (HWND) context[1]);
+
+  // Tell the progress page that we're done running scripts
+  Progress.PostMessage (WM_APP_POSTINSTALL_THREAD_COMPLETE);
+
+  ExitThread(0);
 }
+
+static HANDLE context[2];
+
+void
+do_postinstall (HINSTANCE h, HWND owner)
+{
+  context[0] = h;
+  context[1] = owner;
+
+  DWORD threadID;
+  CreateThread (NULL, 0, do_postinstall_reflector, context, 0, &threadID);
+}
+
Index: script.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/script.cc,v
retrieving revision 2.7
diff -u -p -r2.7 script.cc
--- script.cc	20 Mar 2003 10:02:51 -0000	2.7
+++ script.cc	25 Mar 2003 01:24:28 -0000
@@ -182,13 +182,8 @@ run (const char *sh, const char *args, c
       si.hStdOutput = file_out.handle ();
       si.hStdError = file_out.handle ();
       si.dwFlags |= STARTF_USESHOWWINDOW;
-#if 0
       si.wShowWindow = SW_HIDE;
-      flags = CREATE_NO_WINDOW;  // Note: might not work on Win9x
-#else
-      // TODO: introduce a script progress tracker and use the above
-      si.wShowWindow = SW_MINIMIZE;
-#endif
+      flags = CREATE_NO_WINDOW;  // Note: this is ignored on Win9x
     }
 
   BOOL createSucceeded = CreateProcess (0, cmdline, 0, 0, inheritHandles,
@@ -250,11 +245,14 @@ try_run_script (String const &dir, Strin
     run_script (dir.cstr_oneuse(), (fname + ".bat").cstr_oneuse());
 }
 
+char const Script::ETCPostinstall[] = "/etc/postinstall/";
+
 bool
 Script::isAScript (String const &file)
 {
     /* file may be /etc/postinstall or etc/postinstall */
-    if (file.casecompare ("/etc/postinstall/", 17) && file.casecompare ("etc/postinstall/", 16))
+    if (file.casecompare (ETCPostinstall, sizeof(ETCPostinstall)) &&
+	file.casecompare (ETCPostinstall+1, sizeof(ETCPostinstall)-1))
       return false;
     if (file.cstr_oneuse()[file.size() - 1] == '/')
       return false;
@@ -267,10 +265,23 @@ Script::Script (String const &fileName) 
 }
 
 String
-Script::baseName()const
+Script::baseName() const
 {
   String result = scriptName;
   while (result.find ('/'))
     result = result.substr(result.find ('/'));
   return result;
 }
+
+String
+Script::fullName() const
+{
+  return scriptName;
+}
+
+void
+Script::run(BOOL to_log) const
+{
+  run_script("", scriptName, to_log);
+}
+
Index: script.h
===================================================================
RCS file: /cvs/cygwin-apps/setup/script.h,v
retrieving revision 2.4
diff -u -p -r2.4 script.h
--- script.h	20 Mar 2003 10:02:51 -0000	2.4
+++ script.h	25 Mar 2003 01:24:28 -0000
@@ -30,12 +30,15 @@ void init_run_script ();
 void try_run_script (String const &dir, String const &fname);
 
 class Script {
-  public:
-    static bool isAScript (String const &file);
-    Script (String const &fileName);
-    String baseName()const;
-  private:
-    String scriptName;
+public:
+  static bool isAScript (String const &file);
+  Script (String const &fileName);
+  String baseName() const;
+  String fullName() const;
+  void run(BOOL to_log = FALSE) const;
+private:
+  String scriptName;
+  static char const ETCPostinstall[];
 };
 
 #endif /* SCRIPT_H */
Index: threebar.cc
===================================================================
RCS file: /cvs/cygwin-apps/setup/threebar.cc,v
retrieving revision 2.4
diff -u -p -r2.4 threebar.cc
--- threebar.cc	26 Jun 2002 21:35:16 -0000	2.4
+++ threebar.cc	25 Mar 2003 01:24:28 -0000
@@ -172,6 +172,18 @@ bool
       }
     case WM_APP_INSTALL_THREAD_COMPLETE:
       {
+	// Install is complete and we want to go on to the postinstall.
+	Window::PostMessage (WM_APP_START_POSTINSTALL);
+	break;
+      }
+    case WM_APP_START_POSTINSTALL:
+      {
+	// Start the postinstall script thread.
+	do_postinstall (GetInstance (), GetHWND ());
+	break;
+      }
+    case WM_APP_POSTINSTALL_THREAD_COMPLETE:
+      {
 	// Re-enable and "Push" the Next button
 	GetOwner ()->SetButtons (PSWIZB_NEXT);
 	GetOwner ()->PressButton (PSBTN_NEXT);
Index: threebar.h
===================================================================
RCS file: /cvs/cygwin-apps/setup/threebar.h,v
retrieving revision 2.4
diff -u -p -r2.4 threebar.h
--- threebar.h	21 Sep 2002 09:36:46 -0000	2.4
+++ threebar.h	25 Mar 2003 01:24:29 -0000
@@ -32,6 +32,8 @@
 #define WM_APP_START_SETUP_INI_DOWNLOAD    WM_APP+6
 #define WM_APP_SETUP_INI_DOWNLOAD_COMPLETE WM_APP+7
 // desktop.h: WM_APP_UNATTENDED_FINISH WM_APP+8
+#define WM_APP_START_POSTINSTALL           WM_APP+9
+#define WM_APP_POSTINSTALL_THREAD_COMPLETE WM_APP+10
 
 class ThreeBarProgressPage:public PropertyPage
 {


More information about the Cygwin-apps mailing list