def start(url, user, password, local_product_folder, refresh_type="forced", dependencies=[], run_once=False):
    import warnings

    warnings.warn("This is dying. Use start_multiple() instead", DeprecationWarning)

    import ZPublisher.Client

    global ServerError
    ServerError = ZPublisher.Client.ServerError
    objects = [ZPublisher.Client.Object(url, username=user, password=password)]

    from Globals import DevelopmentMode

    if url.endswith("/"):
        url = url[:-1]

    if isinstance(dependencies, basestring):
        dependencies = [dependencies]

    # if dependency:
    #    dependencies.append(dependency)

    #
    # this dependency list is expected to be a list of urls
    # that start like the 'url' variable does. If that's not the case,
    # fix them.
    baseurl = "/".join(url.split("/")[:-1])
    for i in range(len(dependencies)):
        if not dependencies[i].startswith(baseurl):
            dependencies[i] = baseurl + "/" + dependencies[i]

    for dep_url in dependencies:
        objects.append(ZPublisher.Client.Object(dep_url, username=user, password=password))

    if refresh_type == "clever" and DevelopmentMode:
        # cool, then we don't have refresh when there's a change to
        # templates like .dtml and .zpt
        mtimer.EXTENSIONS_TO_SCAN = ("sql", "py")

    c = 0
    while 1:
        try:
            sleeptime = int(open("sleeptime.conf").read())
        except:
            sleeptime = 5

        if mtimer.run(local_product_folder) == "Different":
            print refresh_product(objects),
            print "(%s)" % (seconds2time(c))

        if run_once:
            break

        time.sleep(sleeptime)
        open("sleeptime.conf", "w").write(str(sleeptime))
        c += sleeptime
def start_multiple(products, user, password, refresh_type="forced", run_once=False, mtimer_options={}):
    """ similar to start() but using multiple configurations """
    import ZPublisher.Client
    from Globals import DevelopmentMode

    global ServerError
    ServerError = ZPublisher.Client.ServerError
    # objects=[ZPublisher.Client.Object(url, username=user, password=password)]

    products_by_path = {}
    for product in products:
        key = product["productpath"]
        url = product["CTurl"]

        dependencies = product.get("dependencies", None)
        if isinstance(dependencies, basestring):
            dependencies = [dependencies]
        elif isinstance(dependencies, tuple):
            dependencies = list(dependencies)

        if dependencies:
            #
            # this dependency list is expected to be a list of urls
            # that start like the 'url' variable does. If that's not the case,
            # fix them.
            baseurl = "/".join(url.split("/")[:-1])
            for i in range(len(dependencies)):
                if not dependencies[i].startswith(baseurl):
                    dependencies[i] = baseurl + "/" + dependencies[i]

        if url.endswith("/"):
            url = url[:-1]
        products_by_path[key] = product
        objects = [ZPublisher.Client.Object(url, username=user, password=password)]
        products_by_path[key]["pre_run_command"] = product.get("pre_run_command")
        products_by_path[key]["post_run_command"] = product.get("post_run_command")
        if dependencies:
            for dep_url in dependencies:
                objects.append(ZPublisher.Client.Object(dep_url, username=user, password=password))

        # products_by_path[key]['dependencies'] = dependencies # cleaned up
        products_by_path[key]["objects"] = objects

    if _has_inotify:
        extensions_to_scan = ("sql", "py", "zpt", "dtml", "pt", "js")

    if refresh_type == "clever" and DevelopmentMode:
        # cool, then we don't have refresh when there's a change to
        # templates like .dtml and .zpt
        if _has_inotify:
            extensions_to_scan = ("sql", "py", "js", "css")
        else:
            mtimer.EXTENSIONS_TO_SCAN = ("sql", "py", "css", "js")
            mtimer.FOLDERS_TO_SKIP = ("tests", ".autogenerated", "zpt", "dtml") + mtimer.FOLDERS_TO_SKIP
    else:
        mtimer.FOLDERS_TO_SKIP = ("tests", ".autogenerated") + mtimer.FOLDERS_TO_SKIP

    c = 0

    if _has_inotify and not run_once:
        notifier = Inotify()
        mask = Inotify.IN_MODIFY
        for product_path, config in products_by_path.items():
            assert os.path.isdir(product_path), "product path does not exist %s" % product_path
            _recursiveAddWatch(notifier, product_path, mask)

        while 1:
            events = notifier.read_events()
            for event in events:
                event_string = notifier.event_string(event[Inotify.MASK])
                path_wid = notifier.file(event[Inotify.WID])
                file_wid = event[Inotify.FILE]
                file_wid_extension = file_wid.split(".")[-1]
                if file_wid_extension in extensions_to_scan:
                    # the path might be 'Products/Foo/zpt/widgets' when the product
                    # path is just 'Products/Foo'
                    for product_path, config in products_by_path.items():
                        if path_wid.startswith(product_path):
                            _file_path = os.path.join(path_wid, file_wid).replace("Products/", "")
                            print _file_path,
                            t0 = time.time()
                            r = refresh_product(
                                config["objects"], config["pre_run_command"], config["post_run_command"]
                            )
                            t1 = time.time()
                            log("%s:%s:%s" % (_file_path, t1 - t0, time.time()))
                            if r:
                                print r
                            else:
                                print "done"
                            # print event_string
                            break

    else:

        def _getSleeptime():
            try:
                return float(open("sleeptime.conf").read().split()[0])
            except:
                return 4.0  # seconds

        def _saveSleeptime(sleeptime):
            open("sleeptime.conf", "w").write(str(sleeptime))

        delta = 0.0
        product_info = {}
        while 1:
            try:
                sleeptime = _getSleeptime()
                for product_path, config in products_by_path.items():
                    # t0=time.time()
                    difference, info = mtimer.run(
                        product_path, prev_info=product_info.get(product_path, None), **mtimer_options
                    )
                    product_info[product_path] = info
                    if difference == "Different":
                        t0 = time.time()
                        refresh_product(config["objects"], config["pre_run_command"], config["post_run_command"]),
                        t1 = time.time()
                        print "(%s)" % (seconds2time(c))
                        log("%s:%s:%s" % (product_path, t1 - t0, time.time()))
                        delta = 0.0
                    # print time.time()-t0, "in", product_path

                if run_once:
                    break

                # print "Sleep(%s)" % sleeptime
                time.sleep(sleeptime + delta)  # ; print "sleep", sleeptime + delta

                # every time there's. For every loop, increase the sleeptime with
                # a tiny delta that can't be bigger than the sleeptime.
                # this min() makes sure the extra time never exceeds the original
                # sleeptime. This means that if you leave this running for a very
                # long time the (sleeptime+delta) === sleeptime*2
                delta = min(delta + sleeptime / 200.0, sleeptime)

                c += sleeptime
            except KeyboardInterrupt:
                break