sebastien - in flumotion/branches/transcoder-1: . flumotion/common flumotion/component flumotion/component/combiners flumotion/component/combiners/switch flumotion/component/misc/httpfile flumotion/component/producers/playlist flumotion/extern/log flumotion/launch flumotion/manager flumotion/test flumotion/worker

flumotion-commit at lists.fluendo.com flumotion-commit at lists.fluendo.com
Thu May 10 18:25:27 CEST 2007


Author: sebastien
Date: Thu May 10 18:25:19 2007
New Revision: 4931

Added:
   flumotion/branches/transcoder-1/flumotion/component/combiners/   (props changed)
      - copied from r4929, flumotion/trunk/flumotion/component/combiners/
   flumotion/branches/transcoder-1/flumotion/component/combiners/Makefile.am
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/Makefile.am
   flumotion/branches/transcoder-1/flumotion/component/combiners/__init__.py
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/__init__.py
   flumotion/branches/transcoder-1/flumotion/component/combiners/switch/   (props changed)
      - copied from r4929, flumotion/trunk/flumotion/component/combiners/switch/
   flumotion/branches/transcoder-1/flumotion/component/combiners/switch/Makefile.am
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/switch/Makefile.am
   flumotion/branches/transcoder-1/flumotion/component/combiners/switch/__init__.py
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/switch/__init__.py
   flumotion/branches/transcoder-1/flumotion/component/combiners/switch/admin_gtk.py
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/switch/admin_gtk.py
   flumotion/branches/transcoder-1/flumotion/component/combiners/switch/switch.py
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/switch/switch.py
   flumotion/branches/transcoder-1/flumotion/component/combiners/switch/switch.xml
      - copied unchanged from r4929, flumotion/trunk/flumotion/component/combiners/switch/switch.xml
Modified:
   flumotion/branches/transcoder-1/ChangeLog
   flumotion/branches/transcoder-1/configure.ac
   flumotion/branches/transcoder-1/flumotion/common/config.py
   flumotion/branches/transcoder-1/flumotion/common/enum.py
   flumotion/branches/transcoder-1/flumotion/common/errors.py
   flumotion/branches/transcoder-1/flumotion/component/Makefile.am
   flumotion/branches/transcoder-1/flumotion/component/component.xml
   flumotion/branches/transcoder-1/flumotion/component/feedcomponent010.py
   flumotion/branches/transcoder-1/flumotion/component/misc/httpfile/file.py
   flumotion/branches/transcoder-1/flumotion/component/producers/playlist/playlistparser.py
   flumotion/branches/transcoder-1/flumotion/extern/log/ChangeLog
   flumotion/branches/transcoder-1/flumotion/extern/log/log.py
   flumotion/branches/transcoder-1/flumotion/extern/log/test_log.py
   flumotion/branches/transcoder-1/flumotion/launch/main.py
   flumotion/branches/transcoder-1/flumotion/manager/admin.py
   flumotion/branches/transcoder-1/flumotion/manager/component.py
   flumotion/branches/transcoder-1/flumotion/manager/depgraph.py
   flumotion/branches/transcoder-1/flumotion/manager/main.py
   flumotion/branches/transcoder-1/flumotion/manager/manager.py
   flumotion/branches/transcoder-1/flumotion/test/test_manager_depgraph.py
   flumotion/branches/transcoder-1/flumotion/test/test_misc_httpfile.py
   flumotion/branches/transcoder-1/flumotion/worker/main.py
Log:
2007-05-10  Sebastien Merle  <sebastien at fluendo.com>

	* Merged flumotion trunk changesets up to [4929].


Modified: flumotion/branches/transcoder-1/ChangeLog
==============================================================================
--- flumotion/branches/transcoder-1/ChangeLog	(original)
+++ flumotion/branches/transcoder-1/ChangeLog	Thu May 10 18:25:19 2007
@@ -1,3 +1,7 @@
+2007-05-10  Sebastien Merle  <sebastien at fluendo.com>
+
+	* Merged flumotion trunk changesets up to [4929].
+
 2007-05-09  Sebastien Merle  <sebastien at fluendo.com>
 
 	* flumotion/manager/admin.py: 
@@ -26,6 +30,42 @@
 	* flumotion/manager/admin.py: 
 	Added the loadComponent method.
 
+2007-05-10  Zaheer Abbas Merali  <<zaheerabbas at merali dot org>>
+
+	* flumotion/component/Makefile.am:
+	* flumotion/component/component.xml:
+	Fix distcheck and fix bundling of switch component.
+
+2007-05-10  Zaheer Abbas Merali  <<zaheerabbas at merali dot org>>
+
+	* configure.ac:
+	* flumotion/component/combiners/Makefile.am:
+	* flumotion/component/combiners/__init__.py:
+	* flumotion/component/combiners/switch/Makefile.am:
+	* flumotion/component/combiners/switch/__init__.py:
+	* flumotion/component/combiners/switch/admin_gtk.py (SwitchingNode,
+	  SwitchingNode.__init__, SwitchingNode.cb_toggled,
+	  SwitchingNode.setUIState, SwitchingNode.stateSet, SwitcherAdminGtk,
+	  SwitcherAdminGtk.setup):
+	* flumotion/component/combiners/switch/switch.py (SwitchMedium,
+	  SwitchMedium.remote_switchToMaster,
+	  SwitchMedium.remote_switchToBackup, Switch, Switch.init,
+	  Switch.do_check, Switch.cb, Switch.switchToMaster,
+	  Switch.switchToBackup, SingleSwitch, SingleSwitch.init,
+	  SingleSwitch.get_pipeline_string, SingleSwitch.configure_pipeline,
+	  SingleSwitch.switchToMaster, SingleSwitch.switchToBackup, AVSwitch,
+	  AVSwitch.init, AVSwitch.get_pipeline_string,
+	  AVSwitch.configure_pipeline, AVSwitch.switchToMaster,
+	  AVSwitch.switchToBackup):
+	* flumotion/component/combiners/switch/switch.xml:
+	Add switching components with very simple gtk admin for now.
+
+2007-05-10  Sebastien Merle  <sebastien at fluendo.com>
+
+	* flumotion/common/enum.py: 
+	Made the unjellyer an diffrent class than Enum, because
+	Twsited 2.0.1 need the unjellyer to be a classic style class.
+
 2007-03-30  Sebastien Merle  <sebastien at fluendo.com>
 
 	* flumotion/common/enum.py: 
@@ -44,6 +84,51 @@
 	be jellyed and unjellyed. Now an enum value can be directly 
 	used with spread without converting to int.
 
+2007-05-09  Andy Wingo  <wingo at pobox.com>
+
+	* flumotion/worker/main.py (main): 
+	* flumotion/launch/main.py (main): 
+	* flumotion/manager/main.py (main): --verbose sets a baseline for
+	--debug, not overriding it. Fixes #82.
+
+	* flumotion/manager/component.py (ComponentAvatar.cleanup): Add a
+	comment.
+
+2007-05-09  Zaheer Abbas Merali  <<zaheerabbas at merali dot org>>
+
+	* flumotion/test/test_manager_depgraph.py
+	  (testDepGraph._createComponent):
+	Fix tests for depgraph to use the eater key.
+
+2007-05-09  Zaheer Abbas Merali  <<zaheerabbas at merali dot org>>
+
+	* flumotion/component/feedcomponent010.py
+	  (FeedComponent.get_eater_name_for_feedid):
+	Add helper method.
+	* flumotion/manager/depgraph.py (DepGraph.mapEatersToFeeders,
+	  DepGraph.whatShouldBeStarted):
+	Migrate depgraph to use the eater key rather than the source key.
+
+2007-05-09  Michael Smith <msmith at fluendo.com>
+
+	* flumotion/component/producers/playlist/playlistparser.py:
+	  Fix duration adjustment for making sources fit into timeline.
+
+2007-05-09  Thomas Vander Stichele  <thomas at apestaart dot org>
+
+	* flumotion/component/misc/httpfile/file.py (File.renderAuthenticated,
+	  File.do_prepareBody, MimedFileFactory, FLVFile,
+	  FLVFile.do_prepareBody, FileTransfer):
+	  Make sure start= requests on FLV files give me the right mime type
+	  by not writing before all headers are set.
+	  factor out an overridable do_prepareBody in which FLV and the like
+	  can do their manipulative trickery.
+	  Re-fixes #618.
+	* flumotion/test/test_misc_httpfile.py (TestTextFile.finishCallback,
+	  TestDirectory.finish, TestDirectory.finish, TestDirectory.finish,
+	  TestDirectory.testFLVRangeStart, TestDirectory.finish):
+	  Add tests.  Be more assertive.
+
 2007-05-09  Michael Smith <msmith at fluendo.com>
 
 	* flumotion/component/producers/playlist/playlist.py:

Modified: flumotion/branches/transcoder-1/configure.ac
==============================================================================
--- flumotion/branches/transcoder-1/configure.ac	(original)
+++ flumotion/branches/transcoder-1/configure.ac	Thu May 10 18:25:19 2007
@@ -174,6 +174,8 @@
 flumotion/component/effects/colorbalance/Makefile
 flumotion/component/effects/volume/Makefile
 flumotion/component/encoders/Makefile
+flumotion/component/combiners/Makefile
+flumotion/component/combiners/switch/Makefile
 flumotion/component/consumers/Makefile
 flumotion/component/consumers/disker/Makefile
 flumotion/component/consumers/httpstreamer/Makefile

Modified: flumotion/branches/transcoder-1/flumotion/common/config.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/common/config.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/common/config.py	Thu May 10 18:25:19 2007
@@ -62,7 +62,7 @@
 
 def _buildComponentConfig(parentName, componentType, componentName, 
                           componentProperties, componentPlugs=None,
-                          eaters=None, isClockMaster=None, 
+                          eaters=None, isClockMaster=False, 
                           flumotionVersion=None):
     """
     Build a component configuration dictionary.
@@ -139,8 +139,7 @@
             raise ConfigError("%s: unknown type '%s' for property %s"
                               % (componentName, definition.type, name))
         checker = _property_checkers.get(definition.type)
-        #Don't check for tuple because fraction are tuple but are values
-        #if value and (isinstance(value, tuple) or isinstance(value, list)):
+        #Don't check for tuple because fractions are tuple values
         if value and isinstance(value, list):
             if not definition.multiple and len(value) > 1:
                 raise ConfigError("%s: multiple value specified but not "

Modified: flumotion/branches/transcoder-1/flumotion/common/enum.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/common/enum.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/common/enum.py	Thu May 10 18:25:19 2007
@@ -45,8 +45,8 @@
         self.__enums__[value] = enum
         setattr(self, enum.name, enum)
 
+class Enum(object, jelly.Jellyable):
 
-class Enum(object, jelly.Jellyable, jelly.Unjellyable):
     __metaclass__ = EnumMetaClass
     def __init__(self, value, name, nick=None):
         self.value = value
@@ -78,19 +78,6 @@
             self.value, self.name, self.nick])
         return jellier.preserve(self, sxp)
 
-    def unjellyFor(self, unjellier, jellyList):
-        enumClassName, value, name, nick = jellyList[1:]
-        enumClass = _enumClassRegistry.get(enumClassName, None)
-        if enumClass:
-            enum = enumClass.get(value)
-            assert enum.name == name, "Inconsistent Enum Name"
-            return enum
-        self._enumClassName = enumClassName
-        self.value = value
-        self.name = name
-        self.nick = nick
-        return self
-
 
 class EnumClass(object):
     def __new__(klass, type_name, names=(), nicks=(), **extras):
@@ -121,4 +108,25 @@
         _enumClassRegistry[type_name] = etype
         return etype
 
-jelly.setUnjellyableForClass(qual(Enum), Enum)
+
+# Enum unjellyer should not be a new style class,
+# otherwise Twsited 2.0.1 will not recognise it.
+class EnumUnjellyer(jelly.Unjellyable):
+    
+    def unjellyFor(self, unjellier, jellyList):
+        enumClassName, value, name, nick = jellyList[1:]
+        enumClass = _enumClassRegistry.get(enumClassName, None)
+        if enumClass:
+            enum = enumClass.get(value)
+            assert enum.name == name, "Inconsistent Enum Name"
+            return enum
+        # Become a generic Enum instance
+        self.__class__ = Enum
+        self._enumClassName = enumClassName
+        self.value = value
+        self.name = name
+        self.nick = nick
+        return self
+
+
+jelly.setUnjellyableForClass(qual(Enum), EnumUnjellyer)

Modified: flumotion/branches/transcoder-1/flumotion/common/errors.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/common/errors.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/common/errors.py	Thu May 10 18:25:19 2007
@@ -165,7 +165,7 @@
     args[1]: str
     """
 
-class ComponentDuplicatedError(ComponentError):
+class ComponentAlreadyExistsError(ComponentError):
     """
     A component name is already used.
     """

Modified: flumotion/branches/transcoder-1/flumotion/component/Makefile.am
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/component/Makefile.am	(original)
+++ flumotion/branches/transcoder-1/flumotion/component/Makefile.am	Thu May 10 18:25:19 2007
@@ -17,6 +17,7 @@
 SUBDIRS = \
 	base \
 	bouncers \
+	combiners \
 	consumers \
 	converters \
 	effects \

Modified: flumotion/branches/transcoder-1/flumotion/component/component.xml
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/component/component.xml	(original)
+++ flumotion/branches/transcoder-1/flumotion/component/component.xml	Thu May 10 18:25:19 2007
@@ -13,6 +13,7 @@
           <filename location="converters/__init__.py" />
           <filename location="encoders/__init__.py" />
           <filename location="muxers/__init__.py" />
+	  <filename location="combiners/__init__.py" />
           <filename location="consumers/__init__.py" />
           <filename location="bouncers/__init__.py" />
           <filename location="effects/__init__.py" />

Modified: flumotion/branches/transcoder-1/flumotion/component/feedcomponent010.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/component/feedcomponent010.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/component/feedcomponent010.py	Thu May 10 18:25:19 2007
@@ -1308,4 +1308,9 @@
                 self._gotFirstNewSegment[feedId] = True
         return True
 
+    def get_eater_name_for_feedid(self, feedId):
+        if self._eaterMapping.has_key(feedId):
+            return self._eaterMapping[feedId]
+        return None
+
 pygobject.type_register(FeedComponent)

Modified: flumotion/branches/transcoder-1/flumotion/component/misc/httpfile/file.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/component/misc/httpfile/file.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/component/misc/httpfile/file.py	Thu May 10 18:25:19 2007
@@ -22,17 +22,19 @@
 import string
 import os
 
+from twisted.web import resource, server, http
+from twisted.web import error as weberror, static
+from twisted.internet import defer, reactor, error, abstract
+from twisted.python import filepath
+from twisted.cred import credentials
+
+from flumotion.configure import configure
 from flumotion.component import component
 from flumotion.common import log, messages, errors, netutils
 from flumotion.component.component import moods
 from flumotion.component.misc.porter import porterclient
 from flumotion.component.base import http as httpbase
-from twisted.web import resource, server, http
-from twisted.web import error as weberror, static
-from twisted.internet import defer, reactor, error, abstract
-from twisted.python import filepath
 from flumotion.twisted import fdserver
-from twisted.cred import credentials
 
 # add our own mime types to the ones parsed from /etc/mime.types
 def loadMimeTypes():
@@ -103,11 +105,7 @@
 
         return server.NOT_DONE_YET
 
-    def renderAuthenticated(self, _, request, first=0):
-        """
-        @type  first: int
-        @param first: starting byte to send from
-        """
+    def renderAuthenticated(self, _, request):
         # Now that we're authenticated (or authentication wasn't requested), 
         # write the file (or appropriate other response) to the client.
         # We override static.File to implement Range requests, and to get access
@@ -120,7 +118,7 @@
         self.restat()
 
         ext = os.path.splitext(self.basename())[1].lower()
-        type = self.contentTypes.get(ext, self.defaultType)
+        contentType = self.contentTypes.get(ext, self.defaultType)
 
         if not self.exists():
             self.debug("Couldn't find resource %s", self.path)
@@ -135,12 +133,14 @@
         # that the client must not issue further requests. 
         # We do this because future requests on this server might actually need
         # to go to a different process (because of the porter)
+        request.setHeader('Server', 'Flumotion/%s' % configure.version)
         request.setHeader('Connection', 'close')
         # We can do range requests, in bytes.
         request.setHeader('Accept-Ranges', 'bytes')
 
-        if type:
-            request.setHeader('content-type', type)
+        if contentType:
+            self.debug('content type %r' % contentType)
+            request.setHeader('content-type', contentType)
 
         try:
             f = self.openForReading()
@@ -156,6 +156,7 @@
 
         fileSize = self.getFileSize()
         # first and last byte offset we will write
+        first = 0
         last = fileSize - 1
 
         range = request.getHeader('range')
@@ -163,6 +164,7 @@
             # We have a partial data request.
             # for interpretation of range, see RFC 2068 14.36
             # examples: bytes=500-999; bytes=-500 (suffix mode; last 500)
+            self.log('range request, %r', range)
             rangeKeyValue = string.split(range, '=')
             if len(rangeKeyValue) != 2:
                 request.setResponseCode(http.REQUESTED_RANGE_NOT_SATISFIABLE)
@@ -203,20 +205,31 @@
             request.setResponseCode(http.PARTIAL_CONTENT)
             request.setHeader('Content-Range', "bytes %d-%d/%d" % 
                 (first, last, fileSize))
-
-        # Start sending from the requested position in the file
-        if first:
-            f.seek(first)
-
-        request.setHeader("Content-Length", str(last - first + 1))
+            # Start sending from the requested position in the file
+            if first:
+                f.seek(first)
+          
+        self.do_prepareBody(request, f, first, last)
 
         if request.method == 'HEAD':
-             return ''
-           
+            return ''
+
         request._transfer = FileTransfer(f, last + 1, request)
 
         return server.NOT_DONE_YET
 
+    def do_prepareBody(self, request, f, first, last):
+        """
+        I am called before the body of the response gets written,
+        and after generic header setting has been done.
+
+        I set Content-Length.
+
+        Override me to send additional headers, or to prefix the body
+        with data headers.
+        """
+        request.setHeader("Content-Length", str(last - first + 1))
+
 class MimedFileFactory(log.Loggable):
     """
     I create File subclasses based on the mime type of the given path.
@@ -250,16 +263,28 @@
     playable.
     """
     header = 'FLV\x01\x01\000\000\000\x09\000\000\000\x09'
-    def renderAuthenticated(self, _, request):
-        self.debug('rendering FLV')
-        first = 0
+
+    def do_prepareBody(self, request, f, first, last):
+        self.log('do_prepareBody for FLV')
+        length = last - first + 1
+
+        # if there is a non-zero start get parameter, prefix the body with
+        # our FLV header
         # each value is a list
         start = int(request.args.get('start', ['0'])[0])
-        if start:
-            first = start
-            request.write(self.header)
+        # range request takes precedence over our start parsing
+        if first == 0 and start:
+            self.debug('start %d passed, seeking', start)
+            f.seek(start)
+            length = last - start + 1 + len(self.header)
+
+        request.setHeader("Content-Length", str(length))
 
-        return File.renderAuthenticated(self, _, request, first=first)
+        if request.method == 'HEAD':
+            return ''
+
+        if first == 0 and start:
+            request.write(self.header)
 
 class FileTransfer:
     """

Modified: flumotion/branches/transcoder-1/flumotion/component/producers/playlist/playlistparser.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/component/producers/playlist/playlistparser.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/component/producers/playlist/playlistparser.py	Thu May 10 18:25:19 2007
@@ -89,8 +89,8 @@
         while item:
             if item.timestamp < newitem.timestamp:
                 prev = item
-            elif (not next and item.timestamp > 
-                    newitem.timestamp + newitem.duration):
+            elif (not next and item.timestamp > newitem.timestamp and 
+                    newitem.timestamp + newitem.duration > item.timestamp):
                 next = item
                 break
             item = item.next
@@ -117,6 +117,8 @@
 
         # Duration adjustments -> Reflect into gnonlin timeline
         if prev and prev.timestamp + prev.duration > newitem.timestamp:
+            self.debug("Changing duration of previous item from %d to %d", 
+                prev.duration, newitem.timestamp - prev.timestamp)
             prev.duration = newitem.timestamp - prev.timestamp
             if prev.asrc:
                 prev.asrc.props.duration = prev.duration
@@ -124,7 +126,9 @@
             if prev.vsrc:
                 prev.vsrc.props.duration = prev.duration
                 prev.vsrc.props.media_duration = prev.duration
-        if next and timestamp + newitem.duration > next.timestamp:
+        if next and newitem.timestamp + newitem.duration > next.timestamp:
+            self.debug("Changing duration of new item from %d to %d to fit", 
+                newitem.duration, next.timestamp - newitem.timestamp)
             newitem.duration = next.timestamp - newitem.timestamp
 
         # Then we need to actually add newitem into the gnonlin timeline

Modified: flumotion/branches/transcoder-1/flumotion/extern/log/ChangeLog
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/extern/log/ChangeLog	(original)
+++ flumotion/branches/transcoder-1/flumotion/extern/log/ChangeLog	Thu May 10 18:25:19 2007
@@ -1,3 +1,22 @@
+2007-05-09  Andy Wingo  <wingo at pobox.com>
+
+	Patch by: Philippe Normand <philippe fluendo.com>
+
+	* log.py (init): Adapt to addLimitedLogHandler.
+	(addLogHandler): Only add generic log handlers.
+	(addLimitedLogHandler): New function, splits out management of
+	limited log handlers.
+	(removeLogHandler, removeLimitedLogHandler): New functions.
+
+	* test_log.py (TestLog.testLimitInvisible)
+	(TestLog.testLimitedVisible, TestLog.testFormatStrings)
+	(TestLog.testLimitedError, TestLog.testLogHandlerLimitedLevels):
+	Limited log handlers are now managed via addLimitedLogHandler.
+	(TestLog.testLogHandler)
+	(TestOwnLogHandler.testOwnLogHandlerLimited)
+	(TestOwnLogHandler.testLogHandlerAssertion): No need for
+	limited=False.
+
 2007-04-30  Andy Wingo  <wingo at pobox.com>
 
 	* log.py (TwistedLogObserver.emit): Write to stderr, like the

Modified: flumotion/branches/transcoder-1/flumotion/extern/log/log.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/extern/log/log.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/extern/log/log.py	Thu May 10 18:25:19 2007
@@ -348,7 +348,7 @@
     if os.environ.has_key(envVarName):
         # install a log handler that uses the value of the environment var
         setDebug(os.environ[envVarName])
-    addLogHandler(stderrHandler, limited=True)
+    addLimitedLogHandler(stderrHandler)
 
     _initialized = True
 
@@ -394,7 +394,7 @@
     _log_handlers_limited = []
     _initialized = False
 
-def addLogHandler(func, limited=True):
+def addLogHandler(func):
     """
     Add a custom log handler.
 
@@ -405,18 +405,65 @@
                     None. Use getLevelName(level) to get a printable
                     name for the log level.
     @type func:     a callable function
-    @type limited:  boolean
-    @param limited: whether to automatically filter based on the DEBUG value
+    @raises:        TypeError if func is not a callable
     """
 
     if not callable(func):
         raise TypeError, "func must be callable"
-    
-    if limited:
-        _log_handlers_limited.append(func)
-    else:
+
+    if func not in _log_handlers:
         _log_handlers.append(func)
- 
+        
+def addLimitedLogHandler(func):
+    """
+    Add a custom log handler.
+
+    @param func:    a function object
+                    with prototype (level, object, category, message)
+                    where level is either ERROR, WARN, INFO, DEBUG, or
+                    LOG, and the rest of the arguments are strings or
+                    None. Use getLevelName(level) to get a printable
+                    name for the log level.
+    @type func:     a callable function
+    @raises:        TypeError if func is not a callable    
+    """
+    if not callable(func):
+        raise TypeError, "func must be callable"
+
+    if func not in _log_handlers_limited:
+        _log_handlers_limited.append(func)
+    
+def removeLogHandler(func):
+    """
+    Remove a registered log handler.
+
+    @param func:    a function object
+                    with prototype (level, object, category, message)
+                    where level is either ERROR, WARN, INFO, DEBUG, or
+                    LOG, and the rest of the arguments are strings or
+                    None. Use getLevelName(level) to get a printable
+                    name for the log level.
+    @type func:     a callable function
+    @raises:        ValueError if func is not registered
+    """
+    _log_handlers.remove(func)
+
+    
+def removeLimitedLogHandler(func):
+    """
+    Remove a registered limited log handler.
+
+    @param func:    a function object
+                    with prototype (level, object, category, message)
+                    where level is either ERROR, WARN, INFO, DEBUG, or
+                    LOG, and the rest of the arguments are strings or
+                    None. Use getLevelName(level) to get a printable
+                    name for the log level.
+    @type func:     a callable function
+    @raises:        ValueError if func is not registered
+    """
+    _log_handlers_limited.remove(func)
+
 # public log functions
 def error(cat, format, *args):
     errorObject(None, cat, format, *args)

Modified: flumotion/branches/transcoder-1/flumotion/extern/log/test_log.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/extern/log/test_log.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/extern/log/test_log.py	Thu May 10 18:25:19 2007
@@ -54,7 +54,7 @@
 
     def testLimitInvisible(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler)
+        log.addLimitedLogHandler(self.handler)
         
         # log 2 we shouldn't get
         self.tester.log("not visible")
@@ -69,7 +69,7 @@
 
     def testLimitedVisible(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler)
+        log.addLimitedLogHandler(self.handler)
         
         # log 3 we should get
         self.tester.info("visible")
@@ -84,7 +84,7 @@
   
     def testFormatStrings(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler)
+        log.addLimitedLogHandler(self.handler)
         
         self.tester.info("%d %s", 42, 'the answer')
         assert self.category == 'testlog'
@@ -93,7 +93,7 @@
   
     def testLimitedError(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler)
+        log.addLimitedLogHandler(self.handler)
         
         self.assertRaises(SystemExit, self.tester.error, "error")
         assert self.category == 'testlog'
@@ -102,7 +102,7 @@
 
     def testLogHandlerLimitedLevels(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler)
+        log.addLimitedLogHandler(self.handler)
         
         # now try debug and log again too
         log.setDebug("testlog:5")
@@ -120,7 +120,7 @@
     # test that we get all log messages
     def testLogHandler(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler, limited=False)
+        log.addLogHandler(self.handler)
 
         self.tester.log("visible")
         assert self.message == 'visible'
@@ -144,13 +144,13 @@
     # test if our own log handler correctly mangles the message
     def testOwnLogHandlerLimited(self):
         log.setDebug("testlog:3")
-        log.addLogHandler(self.handler, limited=False)
+        log.addLogHandler(self.handler)
         
         self.tester.log("visible")
         assert self.message == 'override visible'
   
     def testLogHandlerAssertion(self):
-        self.assertRaises(TypeError, log.addLogHandler, None)
+        self.assertRaises(TypeError, log.addLimitedLogHandler, None)
   
 class TestGetExceptionMessage(unittest.TestCase):
     def func3(self):

Modified: flumotion/branches/transcoder-1/flumotion/launch/main.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/launch/main.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/launch/main.py	Thu May 10 18:25:19 2007
@@ -272,7 +272,7 @@
 
     # verbose overrides --debug
     if options.verbose:
-        options.debug = "*:3"
+        log.setFluDebug("*:3")
  
     # handle all options
     if options.version:

Modified: flumotion/branches/transcoder-1/flumotion/manager/admin.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/manager/admin.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/manager/admin.py	Thu May 10 18:25:19 2007
@@ -411,10 +411,10 @@
 
     def perspective_loadComponent(self, componentType, componentId,
                                   componentProperties, workerName,
-                                  eaters=None, isClockMaster=None):
+                                  eaters=None, isClockMaster=False):
         """
         Load a component into the manager configuration.
-        Returns a deferred that will be call with a LoadingOutcome value.
+        Returns a deferred that will be called with the component state.
         
         @param componentType: the registered type of the component to be added
         @type  componentType: str
@@ -423,12 +423,13 @@
         @type  componentId: str
         @param componentProperties: the properties of the component to be added
         @type  componentProperties: dict of str => str
-        @param workerName: the compName of the worker where the added 
+        @param workerName: the name of the worker where the added 
                            component should run.
         @type  workerName: str
         @param eaters: the stream eaters of the component to be added.
         @type  eaters: dict of str keyed list of str
         @param isClockMaster: if the component to be added is clock master.
+                              By default a componenet is not a clack master.
         @type  isClockMaster: bool
         """
         return self.vishnu.loadComponent(self.remoteIdentity, componentType, 

Modified: flumotion/branches/transcoder-1/flumotion/manager/component.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/manager/component.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/manager/component.py	Thu May 10 18:25:19 2007
@@ -99,6 +99,7 @@
         Clean up when detaching.
         """
         if self._ports:
+            # FIXME: doesn't seem to ever be possible
             self.vishnu.releasePortsOnWorker(self.getWorkerName(),
                                              self._ports.values())
             

Modified: flumotion/branches/transcoder-1/flumotion/manager/depgraph.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/manager/depgraph.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/manager/depgraph.py	Thu May 10 18:25:19 2007
@@ -200,46 +200,41 @@
             # for this component setup, go through all the feeders in it
             config = eatingComponent.get('config')
 
-            if not config.has_key('source'):
+            if not config.has_key('eater'):
                 # no eaters
                 self.debug("Component %r has no eaters" % eatingComponent)
             else:
-                # source is a list of componentName[:feedName]
+                # eater is a dict of eaterName -> list of componentName[:feedName]
                 # with feedName defaulting to default
-                # FIXME: maybe source should really be eaters and contain
-                # a list of feedId
-                list = config['source']
-
-                # FIXME: there's a bug in config parsing - sometimes this gives
-                # us one string, and sometimes a list of one string, and
-                # sometimes a list
-                if isinstance(list, str):
-                    list = [list, ]
-
-                for source in list:
-                    feederFound = False
-                    feederComponentName = source.split(':')[0]
-                    # find the feeder
-                    for feedingComponent in toSetup:
-                        if feedingComponent.get("name") == feederComponentName:
-                            feederFound = True
-                            try:
-                                self._addEdge(feedingComponent, eatingComponent,
-                                    "COMPONENTSETUP", "COMPONENTSETUP")
-                            except KeyError:
-                                # it is possible for a component to have
-                                # two eaters, each eating from feeders on
-                                # one other component
-                                pass
-                            try:
-                                self._addEdge(feedingComponent, eatingComponent,
-                                    "COMPONENTSTART", "COMPONENTSTART")
-                            except KeyError:
-                                pass
-
-                    if not feederFound:
-                        raise errors.ComponentConfigError(eatingComponent,
-                            "No feeder exists for eater %s" % source)
+                eaters = config['eater']
+
+                for eater in eaters:
+                    for feed in eaters[eater]:
+                        feederFound = False
+                        feederComponentName = feed.split(':')[0]
+                        # find the feeder
+                        for feedingComponent in toSetup:
+                            if feedingComponent.get("name") == feederComponentName:
+                                feederFound = True
+                                try:
+                                    self._addEdge(feedingComponent, eatingComponent,
+                                        "COMPONENTSETUP", "COMPONENTSETUP")
+                                except KeyError:
+                                    # it is possible for a component to have
+                                    # two eaters, each eating from feeders on
+                                    # one other component
+                                    pass
+                                try:
+                                    self._addEdge(feedingComponent, eatingComponent,
+                                        "COMPONENTSTART", "COMPONENTSTART")
+                                except KeyError:
+                                    pass
+
+                        if not feederFound:
+                            raise errors.ComponentConfigError(eatingComponent,
+                                "No feeder exists for eater %s on component %s"
+                                " feeding from %s" % (eater, eatingComponent,
+                                feed))
 
     def whatShouldBeStarted(self):
         """

Modified: flumotion/branches/transcoder-1/flumotion/manager/main.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/manager/main.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/manager/main.py	Thu May 10 18:25:19 2007
@@ -154,9 +154,9 @@
             log.debug('manager', 'Setting configure.%s to %s' % (d, o))
             setattr(configure, d, o)
 
-    # verbose overrides --debug
+    # verbose sets a baseline for --debug
     if options.verbose:
-        options.debug = "*:3"
+        log.setFluDebug("*:3")
 
     # Handle options that don't require a configuration file.
     if options.version:

Modified: flumotion/branches/transcoder-1/flumotion/manager/manager.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/manager/manager.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/manager/manager.py	Thu May 10 18:25:19 2007
@@ -470,7 +470,9 @@
         atmosphere = state.get('atmosphere')
         for name, c in conf.atmosphere.components.items():
             if name in [x.get('name') for x in atmosphere.get('components')]:
-                self.debug('atmosphere already has component %s' % name)
+                message = 'atmosphere already has component %s' % name
+                self.debug(message)
+                raise errors.ComponentAlreadyExistsError(message)
             else:
                 added.append(self._addComponent(c, atmosphere, identity))
 
@@ -487,8 +489,10 @@
             components = [x.get('name') for x in flow.get('components')]
             for name, c in f.components.items():
                 if name in components:
-                    self.debug('component %s already in flow %s'
+                    message = ('component %s already in flow %s' 
                                % (c.name, f.name))
+                    self.debug(message)
+                    raise errors.ComponentAlreadyExistsError(message)
                 else:
                     added.append(self._addComponent(c, flow, identity))
 
@@ -551,15 +555,11 @@
 
     def loadComponent(self, identity, componentType, componentId,
                       componentProperties, workerName, 
-                      eaters=None, isClockMaster=None):
+                      eaters=None, isClockMaster=False):
         """
         Load a component into the manager configuration.
-        Returns a deferred that will be call with a LoadingOutcome value.
+        Returns a deferred that will be called with the component state.
         
-        @param identity: The identity making this request. This is used by the
-                         adminaction logging mechanism in order to say who is
-                         performing the action.
-        @type  identity: L{flumotion.common.identity.Identity}
         @param componentType: the registered type of the component to be added
         @type  componentType: str
         @param componentId: the identifier of the component to add, should be 
@@ -573,8 +573,8 @@
         @param eaters: the stream eaters of the component to be added.
         @type  eaters: dict of str keyed list of str
         @param isClockMaster: if the component to be added is clock master.
+                              By default a componenet is not a clack master.
         @type  isClockMaster: bool
-        @return a deferred
         """
         self.debug('loading %s component %s on %s', 
                    componentType, componentId, workerName)
@@ -598,7 +598,7 @@
             if compName in components:
                 message = 'Atmosphere already has component %s' % compName
                 self.debug(message)
-                raise errors.ComponentDuplicatedError(message)
+                raise errors.ComponentAlreadyExistsError(message)
             else:
                 compState = self._addComponent(compConf, atmosphere, identity)
         else:
@@ -616,7 +616,7 @@
                 message = ('Component %s already in flow %s' 
                            % (compName, parentName))
                 self.debug(message)
-                raise errors.ComponentDuplicatedError(message)
+                raise errors.ComponentAlreadyExistsError(message)
             else:
                 compState = self._addComponent(compConf, flow, identity)
         

Modified: flumotion/branches/transcoder-1/flumotion/test/test_manager_depgraph.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/test/test_manager_depgraph.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/test/test_manager_depgraph.py	Thu May 10 18:25:19 2007
@@ -41,7 +41,7 @@
         for eater in defs[4]:
             source.append(eater)
         
-        conf["source"] = source
+        conf["eater"] = {"default":source}
 
         ret.set("config", conf)
         return ret

Modified: flumotion/branches/transcoder-1/flumotion/test/test_misc_httpfile.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/test/test_misc_httpfile.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/test/test_misc_httpfile.py	Thu May 10 18:25:19 2007
@@ -82,6 +82,8 @@
         self.assertEquals(request.data, data)
         self.assertEquals(int(request.getHeader('Content-Length') or '0'),
             length)
+        self.assertEquals(request.getHeader('content-type'),
+            'application/octet-stream')
 
     def finishPartialCallback(self, result, request, data, start, end):
         self.finishCallback(result, request, http.PARTIAL_CONTENT, data)
@@ -199,6 +201,7 @@
         self.assertEquals(self.resource.getChild('test.flv', fr).render(fr),
             server.NOT_DONE_YET)
         def finish(result):
+            self.assertEquals(fr.getHeader('content-type'), 'video/x-flv')
             self.assertEquals(fr.data, 'a fake FLV file')
         fr.finishDeferred.addCallback(finish)
 
@@ -209,7 +212,11 @@
         self.assertEquals(self.resource.getChild('test.flv', fr).render(fr),
             server.NOT_DONE_YET)
         def finish(result):
-            self.assertEquals(fr.data, file.FLVFile.header + 'fake FLV file')
+            self.assertEquals(fr.getHeader('content-type'), 'video/x-flv')
+            expected = file.FLVFile.header + 'fake FLV file'
+            self.assertEquals(fr.data, expected)
+            self.assertEquals(fr.getHeader('Content-Length'),
+                str(len(expected)))
         fr.finishDeferred.addCallback(finish)
 
         return fr.finishDeferred
@@ -219,7 +226,21 @@
         self.assertEquals(self.resource.getChild('test.flv', fr).render(fr),
             server.NOT_DONE_YET)
         def finish(result):
+            self.assertEquals(fr.getHeader('content-type'), 'video/x-flv')
             self.assertEquals(fr.data, 'a fake FLV file')
         fr.finishDeferred.addCallback(finish)
+        return fr.finishDeferred
 
+    def testFLVRangeStart(self):
+        # range should take precedence over start parameter
+        fr = FakeRequest(headers={'range': 'bytes=7-'}, args={'start': [2]})
+        self.assertEquals(self.resource.getChild('test.flv', fr).render(fr),
+            server.NOT_DONE_YET)
+        def finish(result):
+            self.assertEquals(fr.getHeader('content-type'), 'video/x-flv')
+            expected = 'FLV file'
+            self.assertEquals(fr.data, expected)
+            self.assertEquals(fr.getHeader('Content-Length'),
+                str(len(expected)))
+        fr.finishDeferred.addCallback(finish)
         return fr.finishDeferred

Modified: flumotion/branches/transcoder-1/flumotion/worker/main.py
==============================================================================
--- flumotion/branches/transcoder-1/flumotion/worker/main.py	(original)
+++ flumotion/branches/transcoder-1/flumotion/worker/main.py	Thu May 10 18:25:19 2007
@@ -168,9 +168,8 @@
             log.debug('worker', 'Setting configure.%s to %s' % (d, o))
             setattr(configure, d, o)
 
-    # verbose overrides --debug; is only a command-line option
     if options.verbose:
-        options.debug = "*:3"
+        log.setFluDebug("*:3")
  
     # apply the command-line debug level if is given through --verbose or -d
     if options.debug:


More information about the flumotion-commit mailing list