Index: umc/python/online/__init__.py =================================================================== --- umc/python/online/__init__.py (revision 3582) +++ umc/python/online/__init__.py (working copy) @@ -104,8 +104,8 @@ 'logfile': '/var/log/univention/updater.log', 'statusfile': '/var/lib/univention-updater/univention-updater.status' }, - # no API available, and no wrapper-wrapper too (or at least, didn't find one). - # Should I write a wrapper, especially to get consistent behaviour in terms of 'logfile' and 'statusfile'? + # *** IMPORTANT! *** the arg list from our request contains the COMPONENT name but the command + # here must contain the list of DEFAULTPACKAGES! # cmd = '/usr/share/univention-updater/univention-updater-umc-univention-install %s' % (' '.join(pkglist)) 'component': { 'purpose': _("Install component '%s'"), @@ -843,16 +843,18 @@ MODULE.info(" << %s" % s) # ----------------------------------- result = None - job = 'unknown' + job = '' if self._current_job and 'job' in self._current_job: job = self._current_job['job'] else: - job = request.options.get('job','none') + job = request.options.get('job','') count = request.options.get('count',0) result = 0 if count < 0 else [] if not job in INSTALLERS: - MODULE.warn(" ?? Don't know a '%s' job" % job) + # job empty: this is the first call I can't avoid + if job != '': + MODULE.warn(" ?? Don't know a '%s' job" % job) else: if not 'logfile' in INSTALLERS[job]: MODULE.warn(" ?? Job '%s' has no associated log file" % job) @@ -900,7 +902,11 @@ job = request.options.get('job','') result = {} if job in INSTALLERS: - result = INSTALLERS[job] + # make a copy, not a reference! + result = {} + for arg in INSTALLERS[job]: + result[arg] = INSTALLERS[job][arg] + if 'statusfile' in INSTALLERS[job]: try: for line in open(INSTALLERS[job]['statusfile']): @@ -944,6 +950,10 @@ result['label'] = result['purpose'] % result['detail'] else: result['label'] = result['purpose'] + # Affordance to reboot... hopefully this gets set before + # we stop polling on this job status + self.ucr.load() # make it as current as possible + result['reboot'] = self.ucr.is_true('update/reboot/required',False) # ----------- DEBUG ----------------- MODULE.info("online/installer/status returns:") @@ -972,13 +982,16 @@ at the top of the file. """ # ----------- DEBUG ----------------- - MODULE.info("online/installer/execute invoked with:") + MODULE.warn("online/installer/execute invoked with:") pp = pprint.PrettyPrinter(indent=4) st = pp.pformat(request.options).split("\n") for s in st: - MODULE.info(" << %s" % s) + MODULE.warn(" << %s" % s) # ----------------------------------- + # Clean up any stored job details ... they're now obsolete. + self._current_job = {} + result = {} result['status'] = 0 # successful. If not: set result['message'] too. @@ -999,11 +1012,32 @@ self.finished(request.id,result) return - cmd = INSTALLERS[subject]['command'] - if cmd.find('%') != -1: - cmd = cmd % request.options.get('detail','') - MODULE.info(" ++ Creating job: '%s'" % cmd) - self.__create_at_job(cmd,detail) + try: + # Assemble the command line, now somewhat complicated: + # + # (1) take the 'command' entry from the INSTALLERS entry of this subject + # (2) if it doesn't contain a percent sign -> ready. + # (3) if it contains a percent sign: we must format something: + # (4) if the subject is about 'component' we must get the 'defaultpackages' + # entry from the UCR tuple named by 'detail' and use that. + # (5) if not, we can format the 'detail' field into the command. + cmd = '%s' % INSTALLERS[subject]['command'] # I need a copy of this string! + if cmd.find('%') != -1: + if subject == 'component': + # Strictly spoken, we can't arrive here if 'defaultpackages' is not set + ucrs = '%s/%s/defaultpackages' % (COMPONENT_BASE,detail) + pkgs = self.ucr.get(ucrs,'') + cmd = cmd % pkgs + MODULE.warn(" Resolution of default packages of the '%s' component:" % detail) + MODULE.warn(" UCRS = '%s'" % ucrs) + MODULE.warn(" PKGS = '%s'" % pkgs) + MODULE.warn(" CMD = '%s'" % cmd) + else: + cmd = cmd % request.options.get('detail','') + MODULE.warn(" ++ Creating job: '%s'" % cmd) + self.__create_at_job(cmd,detail) + except Exception,ex: + MODULE.warn(" ERROR: %s" % str(ex)) # ----------- DEBUG ----------------- MODULE.info("online/installer/execute returns:") @@ -1289,6 +1323,7 @@ script = ''' #:started: %s #:detail: %s +#:command: %s dpkg-statoverride --add root root 0644 /usr/sbin/univention-management-console-web-server dpkg-statoverride --add root root 0644 /usr/sbin/univention-management-console-server dpkg-statoverride --add root root 0644 /usr/sbin/apache2 @@ -1301,7 +1336,7 @@ dpkg-statoverride --remove /usr/sbin/univention-management-console-server dpkg-statoverride --remove /usr/sbin/apache2 chmod +x /usr/sbin/univention-management-console-server /usr/sbin/univention-management-console-web-server /usr/sbin/apache2 -''' % (started,detail,command) +''' % (started,detail,command,command) p1 = subprocess.Popen( [ 'LC_ALL=C at now', ], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True ) (stdout,stderr) = p1.communicate( script ) Index: umc/js/online.js =================================================================== --- umc/js/online.js (revision 3582) +++ umc/js/online.js (working copy) @@ -93,7 +93,6 @@ // waits for the Progress Page to be closed (automatically or by a close button) dojo.connect(this._progress,'stopWatching',dojo.hitch(this, function(tab) { - this._updates.refreshPage(true); this.hideChild(this._progress); this.showChild(this._updates); this.showChild(this._components); @@ -101,6 +100,13 @@ this.selectChild(tab); })); + // waits for the Progress Page to notify us that a job is finished. This + // should immediately refresh the 'Updates' and 'Components' pages. + dojo.connect(this._progress,'jobFinished',dojo.hitch(this, function() { + this._updates.refreshPage(true); + this._components.refreshPage(); + })); + // waits for the Progress Page to notify us that a job is running dojo.connect(this._progress,'jobStarted',dojo.hitch(this, function() { this._switch_to_progress_page(); @@ -238,7 +244,7 @@ { txt += "\n"; txt += "" + upd[i][0] + "\n"; - txt += "" + upd[i][1] + "\n"; + txt += "" + upd[i][1] + "\n"; txt += "\n"; } } @@ -249,7 +255,7 @@ { txt += "\n"; txt += "" + ins[i][0] + "\n"; - txt += "" + ins[i][1] + "\n"; + txt += "" + ins[i][1] + "\n"; txt += "\n"; } } Index: umc/js/_online/ProgressPage.js =================================================================== --- umc/js/_online/ProgressPage.js (revision 3582) +++ umc/js/_online/ProgressPage.js (working copy) @@ -152,6 +152,13 @@ msg += this._statusfile_data(data.result); + // -------------- DEBUG ------------------ +// for (var v in this._last_job) +// { +// msg += ("
   " + v + " = '" + this._last_job[v] + "'"); +// } + // --------------------------------------- + this._head.set('content',msg); this._pane.layout(); @@ -178,7 +185,7 @@ // takes a status structure as returned from the 'online/installer/status' call, // extracts the fields that came directly from the status file (if any) and - // formats them in a readable HTML fashion. + // formats them into a one-liner. Returns an empty string if nothing matches. _statusfile_data: function(data) { var txt = ''; @@ -243,6 +250,10 @@ { if ((this._job_key != '') && (this._last_job)) { + // First thing to do: notify the Module that the job is finished. So it can already + // refresh the 'Updates' and 'Components' pages before the user gets back there. + this.jobFinished(); + // FIXME Manually making empty lines before and after this text; should better be done // by a style or a style class. var msg = " 
"; @@ -256,11 +267,16 @@ msg += this._statusfile_data(this._last_job); + // -------------- DEBUG ------------------ +// for (var v in this._last_job) +// { +// msg += ("
   " + v + " = '" + this._last_job[v] + "'"); +// } + // --------------------------------------- + this._head.set('content',msg); - // for the last time: scroll log view to bottom and stop polling timer. - this._log.scrollToBottom(); - this._log.stopWatching(); + this._log.stopWatching(); // now log is freely scrollable manually //alert("Watching is finished, job is '" + this._job_key + "'"); @@ -281,6 +297,12 @@ jobStarted: function() { }, + // This function will be called when the already opened ProgressPage encounters + // the end of the current job. The online Module listens here and will refresh + // the 'Updates' and 'Components' pages. + jobFinished: function() { + }, + // online Module calls this when the ProgressPage is to be opened. startWatching: function(args) { //alert("ProgressPage::startWatching()"); Index: umc/js/_online/UpdatesPage.js =================================================================== --- umc/js/_online/UpdatesPage.js (revision 3582) +++ umc/js/_online/UpdatesPage.js (working copy) @@ -10,6 +10,7 @@ dojo.declare("umc.modules._online.UpdatesPage", umc.modules._online.Page, { i18nClass: 'umc.modules.online', + _last_reboot: false, postMixInProperties: function() { @@ -507,6 +508,13 @@ on = (on == 'true'); } + // pop a message up whenever the 'on' value changes + if (on != this._last_reboot) + { + alert("Reboot affordance changed to " + on); + this._last_reboot = on; + } + var pane = this._form.getChildren()[0].getChildren()[0]; dojo.toggleClass(pane.domNode,'dijitHidden',! on); Index: umc/js/_online/_LogViewer.js =================================================================== --- umc/js/_online/_LogViewer.js (revision 3582) +++ umc/js/_online/_LogViewer.js (working copy) @@ -186,8 +186,6 @@ // job key can't be an argument here as we don't know it. startWatching: function(interval) { - //alert("LogViewer::StartWatching(" + interval + ")"); - this._check_interval = interval; // clean up any stale display and states from last run this.set('content',this._("... loading log file ...")); @@ -208,6 +206,7 @@ // effectively stops the polling timer. Can be called from outside (if ProgressPage is being closed) // or from inside (as 'uninitialize' handler) stopWatching: function() { + this._check_interval = 0; },