Exemplo n.º 1
0
    def validate(self):

        # current ptask/version
        try:
            area = PTaskArea.current()
            self._current_ptask = PTask.get(area.spec)
            self._current_ptask_version = self._current_ptask.latest_version
        except PTaskError:
            raise ActionError("Unable to find ptask: " + str(self._ptask))

        # source ptask
        if not isinstance(self._ptask, PTask):
            try:
                cur_spec = PTaskArea.current().spec
                full_spec = PTaskSpec.get(self._ptask, relative_to=cur_spec)
                self._ptask = PTask.get(full_spec)
            except PTaskError:
                raise ActionError("Unable to find ptask: " + str(self._ptask))

        # source ptask version
        if isinstance(self._version, PTaskVersion):
            pass
        elif self._version:
            matches = PTaskVersion.list(
                ptask=self._ptask.spec, number=self._version
            )
            if len(matches) != 1:
                raise ActionError(
                    "Unable to find ptask '{p}' at version '{v}'".format(
                        p=self._ptask.spec, v=self._version
                    )
                )
            else:
                self._version = matches[0]
        else:
            self._version = self._ptask.latest_version

        # source subs
        self._match_str = self._match_str.replace("%", ".*")

        all_subs = self._version.subscriptions
        self._subs_to_source = []
        for sub in all_subs:
            if re.search(self._match_str, sub.product_version_spec):
                self._subs_to_source.append(sub)

        if not self._subs_to_source:
            raise ActionAborted("No subscriptions to source.")
Exemplo n.º 2
0
def _import_mari_plugins():

    from dpa.ptask.area import PTaskArea

    # first, get the context
    ptask_area = PTaskArea.current()

    # get a list of mari plugin directories
    plugin_dirs = ptask_area.ancestor_paths(
        'plugins/mari', include_install=False)

    for plugin_dir in reversed(plugin_dirs):

        if not os.path.isdir(plugin_dir):
            continue
        
        file_names = os.listdir(plugin_dir)

        for file_name in file_names:

            # only python files
            if not file_name.endswith(".py"):
                continue
            
            full_path = os.path.join(plugin_dir, file_name)

            module_name = 'mari_plugin_' + file_name.replace(".", "_")

            try:
                module = imp.load_source(module_name, full_path)
            except Exception as e:
                print "Unable to load mari plugin: " + full_path    
                traceback.print_exc()                
Exemplo n.º 3
0
    def get_import_files(cls, session, name, category, representation,
        relative_to=None):

        ptask_area = PTaskArea.current()
        try:
            import_dir = ptask_area.dir(dir_name='import', path=True)
        except PTaskAreaError:
            raise EntityError("Could not find import directory!")

        import_dir = os.path.join(
            import_dir, 'global', name, category, representation.type, 
            representation.resolution
        )

        # get the file in the import_dir
        import_files = os.listdir(import_dir)
        import_files = [f for f in import_files 
            if f.endswith('.' + representation.type)]

        # prepend the import directory to get the full path
        import_files = [os.path.join(import_dir, f) for f in import_files]

        if relative_to:
            import_files = [
                os.path.relpath(f, relative_to) for f in import_files] 

        return import_files
Exemplo n.º 4
0
def _import_nuke_plugins():

    from dpa.ptask.area import PTaskArea

    # first, get the context
    ptask_area = PTaskArea.current()

    # get a list of nuke plugin directories
    plugin_dirs = ptask_area.ancestor_paths('plugins/nuke',
                                            include_install=False)

    for plugin_dir in reversed(plugin_dirs):

        if not os.path.isdir(plugin_dir):
            continue

        file_names = os.listdir(plugin_dir)

        for file_name in file_names:

            # only python files
            if not file_name.endswith(".py"):
                continue

            full_path = os.path.join(plugin_dir, file_name)

            module_name = 'nuke_plugin_' + file_name.replace(".", "_")

            try:
                module = imp.load_source(module_name, full_path)
            except Exception as e:
                print "Unable to load nuke plugin: " + full_path
                traceback.print_exc()
Exemplo n.º 5
0
def queue_submit_cmd(command, queue_name, output_file=None, id_extra=None,
    dt=None):
    """Create and submit a shell script with the given command."""
    
    ptask_area = PTaskArea.current()
    ptask_area.provision(QUEUE)
    script_dir = ptask_area.dir(dir_name=QUEUE)

    unique_id = get_unique_id(ptask_area.spec, id_extra=id_extra, dt=dt)

    script_name = unique_id + '.sh'
    log_name = unique_id + '.log'

    script_path = os.path.join(script_dir, script_name)
    log_path = os.path.join(script_dir, log_name)

    with open(script_path, "w") as script_file:
        script_file.write("#!/bin/bash\n")
        script_file.write(command + "\n") 
        script_file.write("chmod 660 " + output_file + "\n")

    os.chmod(script_path, 0770)

    create_queue_task(queue_name, script_path, unique_id, 
        output_file=output_file, submit=True, log_path=log_path)
Exemplo n.º 6
0
    def setup_cl_args(cls, parser):

        parser.add_argument(
            "spec",
            nargs="?",
            default=PTaskArea.current().spec,
            help="The production task specification."
        )

        parser.add_argument(
            "-s", "--shell", 
            default=ShellFormatters.default().name,
            choices=sorted([f.name for f in ShellFormatters.all()]),
            help="Shell type env commands should target."
        )

        parser.add_argument(
            "-p", "--previous", 
            nargs="?", 
            const="list",
            help="Choose a previous ptask env."
        )

        parser.add_argument(
            "-v", "--version", 
            type=int,
            help="The version of the ptask to print info for."
        )
Exemplo n.º 7
0
    def ptask_area(self):
        """Return the current ptask area for this session."""

        if not hasattr(self, '_ptask_area'):
            self._ptask_area = PTaskArea.current()

        return self._ptask_area
Exemplo n.º 8
0
    def validate(self):

        # current ptask/version
        try:
            area = PTaskArea.current()
            self._current_ptask = PTask.get(area.spec)
            self._current_ptask_version = self._current_ptask.latest_version
        except PTaskError:
            raise ActionError("Unable to find ptask: " + str(self._ptask))

        # source ptask
        if not isinstance(self._ptask, PTask):
            try:
                cur_spec = PTaskArea.current().spec
                full_spec = PTaskSpec.get(self._ptask, relative_to=cur_spec)
                self._ptask = PTask.get(full_spec)
            except PTaskError:
                raise ActionError("Unable to find ptask: " + str(self._ptask))

        # source ptask version
        if isinstance(self._version, PTaskVersion):
            pass
        elif self._version:
            matches = PTaskVersion.list(ptask=self._ptask.spec,
                                        number=self._version)
            if len(matches) != 1:
                raise ActionError(
                    "Unable to find ptask '{p}' at version '{v}'".format(
                        p=self._ptask.spec, v=self._version))
            else:
                self._version = matches[0]
        else:
            self._version = self._ptask.latest_version

        # source subs
        self._match_str = self._match_str.replace("%", ".*")

        all_subs = self._version.subscriptions
        self._subs_to_source = []
        for sub in all_subs:
            if re.search(self._match_str, sub.product_version_spec):
                self._subs_to_source.append(sub)

        if not self._subs_to_source:
            raise ActionAborted("No subscriptions to source.")
Exemplo n.º 9
0
    def execute(self):

        match_specs = self._complete(
            self.spec,
            relative_to=PTaskArea.current().spec,
        )

        if match_specs:
            print " ".join([s for s in match_specs])
Exemplo n.º 10
0
    def execute(self):

        match_specs = self._complete(
            self.spec, 
            relative_to=PTaskArea.current().spec,
        )

        if match_specs:
            print " ".join([s for s in match_specs])
Exemplo n.º 11
0
def get_default_product_name():

    name = "Comp"

    ptask_area = PTaskArea.current()
    if ptask_area:
        name = PTaskSpec.name(ptask_area.spec) + name

    return name
Exemplo n.º 12
0
def get_default_product_name():

    name = "Comp"

    ptask_area = PTaskArea.current()
    if ptask_area:
        name = PTaskSpec.name(ptask_area.spec) + name

    return name
Exemplo n.º 13
0
    def validate(self):

        if not isinstance(self._ptask, PTask):
            try:
                cur_spec = PTaskArea.current().spec
                full_spec = PTaskSpec.get(self._ptask, relative_to=cur_spec)
                self._ptask = PTask.get(full_spec)
            except PTaskError:
                raise ActionError("Could not determine ptask from: {p}".format(
                    p=self._ptask))
Exemplo n.º 14
0
    def log_action(self):

        if not self.__class__.logging:
            return

        # log the command
        msg = "({s})".format(s=PTaskArea.current().spec)
        msg += " " + " ".join(sys.argv)

        self.logger.info(msg)
Exemplo n.º 15
0
    def validate(self):

        if not isinstance(self._ptask, PTask):
            try:
                cur_spec = PTaskArea.current().spec
                full_spec = PTaskSpec.get(self._ptask, relative_to=cur_spec)
                self._ptask = PTask.get(full_spec)
            except PTaskError:
                raise ActionError("Could not determine ptask from: {p}".format(
                    p=self._ptask))
Exemplo n.º 16
0
    def __call__(self, parser, namespace, in_spec, option_string=None):

        # assume the current ptask if not supplied
        if not in_spec:
            in_spec = "."

        cur_spec = PTaskArea.current().spec
        in_spec = in_spec.strip().strip(PTaskSpec.SEPARATOR)
        full_spec = PTaskSpec.get(in_spec, relative_to=cur_spec)

        setattr(namespace, self.dest, full_spec)
Exemplo n.º 17
0
    def validate(self):

        if not self._message:
            raise ActionError("Message can not be empty.")

        try:
            self._sender = User.current()
        except UserError:
            raise ActionError("Could not identify current user.")

        # get ooto notification recipients from the configs
        ptask_area = PTaskArea.current()
        ooto_config = ptask_area.config(
            OOTO_CONFIG_PATH,
            composite_ancestors=True,
            composite_method="append",
        )

        ooto_notify = ooto_config.get('notify', [])
        self._to.extend(ooto_notify)

        # for all usernames specified, make sure they're a valid user,
        # get their email addresses.
        recipients = set()
        for recipient in self._to:
            
            # assume already a valid email address
            if "@" in recipient:
                recipients.add(recipient)
            else:
                try:
                    recipient = User.get(recipient)
                except UserError:
                    raise ActionError(
                        "Could not identify user: "******"\n\nCurrent ptask: {p}".format(p=ptask_area.spec)
        self._message += "\n\n- {s}".format(s=self._sender.full_name)

        self._subject = "OOTO: {fn} ({un})".format(
            fn=self.sender.full_name,
            un=self.sender.username,
        )
Exemplo n.º 18
0
    def __call__(self, parser, namespace, in_spec, option_string=None):

        # assume the current ptask if not supplied
        if not in_spec:
            in_spec = "."

        cur_spec = PTaskArea.current().spec
        in_spec = in_spec.strip().strip(PTaskSpec.SEPARATOR)
        full_spec = PTaskSpec.get(in_spec, relative_to=cur_spec)

        setattr(namespace, self.dest, full_spec)
Exemplo n.º 19
0
def queue_submit_cmd(command, queue_name, output_file=None, id_extra=None):
    """Create and submit a shell script with the given command."""
    
    ptask_area = PTaskArea.current()
    ptask_area.provision(QUEUE)
    script_dir = ptask_area.dir(dir_name=QUEUE)

    now = datetime.datetime.now()

    if not id_extra:
        id_extra = now.strftime("%f")

    unique_id = "{u}_{t}_{s}_{e}".format(
        u=current_username(),
        t=now.strftime("%Y_%m_%d_%H_%M_%S"),
        s=ptask_area.spec.replace('=', '_'),
        e=id_extra,
    )
    script_name = unique_id + '.sh'
    log_name = unique_id + '.log'

    script_path = os.path.join(script_dir, script_name)
    log_path = os.path.join(script_dir, log_name)

    with open(script_path, "w") as script_file:
        script_file.write("#!/bin/bash\n")
        script_file.write(command + "\n") 
        script_file.write("chmod 660 " + output_file + "\n")

    os.chmod(script_path, 0770)

    # ---- submit to the queue

    from cheesyq import DPACheesyQ, DPADataLibrary, DPACheesyQTasks

    data_lib = DPADataLibrary.DjangoLibrary(None)

    render_task = DPACheesyQ.RenderTask()
    render_task.taskid = unique_id
    render_task.logFileName = log_path
    render_task.outputFileName = output_file

    data_lib.set(render_task.taskid, render_task)
    render_task.addTask(script_path)

    os.system("cqresubmittask {qn} {tid}".format(
        qn=queue_name,
        tid=render_task.taskid
    ))
        
    print "Submitted task: " + str(render_task.taskid)
Exemplo n.º 20
0
    def __init__(self):

        ptask_area = PTaskArea.current()
        options_config = ptask_area.config(FAIL_OPTIONS_CONFIG,
            composite_ancestors=True)

        icon_path = IconFactory().disk_path(FAIL_ICON_URI)

        super(FailDialog, self).__init__(
            title='Failure Report',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Submit',
            modal=False,
        )
Exemplo n.º 21
0
    def __init__(self):

        ptask_area = PTaskArea.current()
        options_config = ptask_area.config(OOTO_OPTIONS_CONFIG,
                                           composite_ancestors=True)

        icon_path = IconFactory().disk_path(OOTO_ICON_URI)

        super(OotoDialog, self).__init__(
            title='Out Of The Office (OOTO)',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Submit',
            modal=False,
        )
Exemplo n.º 22
0
    def __init__(self):

        ptask_area = PTaskArea.current()
        options_config = ptask_area.config(OOTO_OPTIONS_CONFIG,
            composite_ancestors=True)

        icon_path = IconFactory().disk_path(OOTO_ICON_URI)

        super(OotoDialog, self).__init__(
            title='Out Of The Office (OOTO)',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Submit',
            modal=False,
        )
Exemplo n.º 23
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        # if we're listing the current ptask's subs, and no versions specified
        if cur_spec == full_spec and not self._versions:
            ptask_ver = DpaVars.ptask_version().get()
            if ptask_ver:
                self._versions = [ptask_ver]

        if not self._versions:
            self._versions = ["latest"]

        # try to get a ptask instance from the db
        try:
            ptask = PTask.get(full_spec)
        except PTaskError as e:
            # fall back to the input spec
            try:
                ptask = PTask.get(self.spec)
            except PTaskError:
                raise ActionError(
                    'Could not determine ptask from: "{s}"'.format(
                        s=self.spec)
                )

        self._ptask = ptask

        if self._versions == ['latest']:
            versions = [self.ptask.latest_version]
        elif self._versions == ['all']:
            versions = self.ptask.versions
        else:
            self._versions = map(int, self._versions)
            versions = [v for v in self.ptask.versions 
                if v.number in self._versions]

        if len(versions) == 0:
            raise ActionError(
                "No matches found for {p} version: {v}".format(
                    p=ptask.spec,
                    v=Style.bright + str(self._versions) + Style.normal,
                )
            )

        self._versions = versions
Exemplo n.º 24
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        # if we're listing the current ptask's subs, and no versions specified
        if cur_spec == full_spec and not self._versions:
            ptask_ver = DpaVars.ptask_version().get()
            if ptask_ver:
                self._versions = [ptask_ver]

        if not self._versions:
            self._versions = ["latest"]

        # try to get a ptask instance from the db
        try:
            ptask = PTask.get(full_spec)
        except PTaskError as e:
            # fall back to the input spec
            try:
                ptask = PTask.get(self.spec)
            except PTaskError:
                raise ActionError(
                    'Could not determine ptask from: "{s}"'.format(
                        s=self.spec))

        self._ptask = ptask

        if self._versions == ['latest']:
            versions = [self.ptask.latest_version]
        elif self._versions == ['all']:
            versions = self.ptask.versions
        else:
            self._versions = map(int, self._versions)
            versions = [
                v for v in self.ptask.versions if v.number in self._versions
            ]

        if len(versions) == 0:
            raise ActionError("No matches found for {p} version: {v}".format(
                p=ptask.spec,
                v=Style.bright + str(self._versions) + Style.normal,
            ))

        self._versions = versions
Exemplo n.º 25
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        if full_spec:
            try:
                product = Product.get(full_spec)
            except ProductError as e:
                # fall back to input spec
                try:
                    product = Product.get(self.spec)
                except ProductError:
                    raise ActionError('Could not determine product from: "{s}"'.format(s=self.spec))
        else:
            product = None

        self._product = product
Exemplo n.º 26
0
def initializePlugin(mobject):

    # read the config, get all the shelf definitions
    ptask_area = PTaskArea.current()
    maya_shelves_config = ptask_area.config(
        config_file=CONFIG_FILE, composite_ancestors=True)

    for (shelf_name, shelf_config) in maya_shelves_config.iteritems():

        shelf = MayaShelf(shelf_name)
        if shelf.exists:
            shelf.delete()

        shelf.create()

        # add all the shelf buttons
        for (button_key, button_config) in shelf_config.iteritems():
            shelf.add_button(**button_config)

        INITIALIZED_SHELVES.append(shelf)
Exemplo n.º 27
0
    def __init__(self):

        ptask_area = PTaskArea.current()
        options_config = ptask_area.config(IMPORT_OPTIONS_CONFIG,
            composite_ancestors=True)

        self.get_files()

        options_config['options']['products'].set('choices', self.sublist.keys())
        options_config['options']['products'].set('default', self.sublist.keys()[0])

        icon_path = IconFactory().disk_path(IMPORT_ICON_URI)

        super(ImportDialog, self).__init__(
            title='Import Product',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Import',
            modal=False,
        )
Exemplo n.º 28
0
def load_toolbars():
    """Load all custom toolbars via config files."""

    ptask_area = PTaskArea.current()
    nuke_toolbar_config = ptask_area.config(config_file=NUKE_TOOLBAR_CONFIG, composite_ancestors=True)

    for (toolbar_name, toolbar_config) in nuke_toolbar_config.iteritems():

        toolbar = nuke.toolbar(toolbar_name)
        for (item_key, item_config) in toolbar_config.iteritems():

            name = item_config.get("label", item_key)
            command = item_config.get("command", "print 'No op'")
            icon = item_config.get("image", None)
            tooltip = item_config.get("annotation", "")

            if icon:
                icon = IconFactory().disk_path(icon)

            toolbar.addCommand(name=name, command=command, icon=icon, tooltip=tooltip)
Exemplo n.º 29
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        if full_spec:
            try:
                product = Product.get(full_spec)
            except ProductError as e:
                # fall back to input spec
                try:
                    product = Product.get(self.spec)
                except ProductError:
                    raise ActionError(
                        'Could not determine product from: "{s}"'.format(
                            s=self.spec))
        else:
            product = None

        self._product = product
Exemplo n.º 30
0
def populate_sub_cache(ptask_version=None, refresh=False):

    if not ptask_version:

        ptask_area = PTaskArea.current()
        ptask = PTask.get(ptask_area.spec)

        if ptask_area.version:
            ptask_version = ptask.version(ptask_area.version)
        else:
            ptask_version = ptask.latest_version

    nuke_file = nuke.root().name()
    nuke_dir = os.path.dirname(nuke_file)

    if refresh or not SUBD_REPR_CACHE:

        for sub in ptask_version.subscriptions:
            for product_repr in sub.product_version.representations:

                product = product_repr.product_version.product

                if product.category != 'imgseq':
                    continue

                product_repr_str = product.name_spec + ' @ ' + \
                    product_repr.type

                if product_repr.resolution != 'none':
                    product_repr_str += PTaskSpec.SEPARATOR + \
                    product_repr.resolution

                sub_import_dir = get_import_dir(product_repr,
                                                product=product,
                                                area=ptask_area,
                                                relative_to=nuke_dir)

                # populate cache lookups
                SUBD_REPR_CACHE.append(product_repr)
                PRODUCT_REPR_STR_TO_PATH[product_repr_str] = \
                    sub_import_dir
Exemplo n.º 31
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        # try to get a ptask instance from the db
        if full_spec:
            try:
                ptask = PTask.get(full_spec)
            except PTaskError as e:
                # fall back to the input spec
                try:
                    ptask = PTask.get(self.spec)
                except PTaskError:
                    raise ActionError(
                        'Could not determine ptask from: "{s}"'.format(
                            s=self.spec))
        else:
            ptask = None

        self._ptask = ptask
Exemplo n.º 32
0
def get_import_dir(product_repr, product=None, area=None, relative_to=None):

    if not area:
        area = PTaskArea.current()

    if not product:
        product = product_repr.product_version.product

    try:
        import_dir = area.dir(dir_name='import', path=True)
    except PTaskAreaError:
        raise Exception("Could not find import directory!")

    import_dir = os.path.join(import_dir, 'global', product.name,
                              product.category, product_repr.type,
                              product_repr.resolution)

    if relative_to:
        import_dir = os.path.relpath(import_dir, relative_to)

    return import_dir
Exemplo n.º 33
0
    def __init__(self):

        ptask_area = PTaskArea.current()
        options_config = ptask_area.config(IMPORT_OPTIONS_CONFIG,
                                           composite_ancestors=True)

        self.get_files()

        options_config['options']['products'].set('choices',
                                                  self.sublist.keys())
        options_config['options']['products'].set('default',
                                                  self.sublist.keys()[0])

        icon_path = IconFactory().disk_path(IMPORT_ICON_URI)

        super(ImportDialog, self).__init__(
            title='Import Product',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Import',
            modal=False,
        )
Exemplo n.º 34
0
    def log_action(self):

        if not self.__class__.logging:
            return

        # try to format the args/kwargs to be readable in the log
        args_str = ""
        if len(self.args):
            args_str += ", ".join([str(a) for a in self.args])
            args_str = "args(" + args_str + ")"
        if len(self.kwargs.keys()):
            kwargs_str = ", ".join(
                sorted([k + '="' + str(v) + '"' 
                    for (k, v) in self.kwargs.items() if v])
            )
            args_str = args_str + " kwargs(" + kwargs_str + ")"

        msg = "({s})".format(s=PTaskArea.current().spec)
        msg += " " + args_str

        # log the action and its args
        self.logger.info(msg)
Exemplo n.º 35
0
    def validate(self):
        
        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        # try to get a ptask instance from the db
        if full_spec:
            try:
                ptask = PTask.get(full_spec)
            except PTaskError as e:
                # fall back to the input spec
                try:
                    ptask = PTask.get(self.spec)
                except PTaskError:
                    raise ActionError(
                        'Could not determine ptask from: "{s}"'.format(
                            s=self.spec)
                    )
        else:
            ptask = None

        self._ptask = ptask
Exemplo n.º 36
0
def get_import_dir(product_repr, product=None, area=None, relative_to=None):

    if not area:
        area = PTaskArea.current()

    if not product:
        product = product_repr.product_version.product

    try:
        import_dir = area.dir(dir_name='import', path=True)
    except PTaskAreaError:
        raise Exception("Could not find import directory!")

    import_dir = os.path.join(
        import_dir, 'global', product.name, product.category, 
        product_repr.type, product_repr.resolution
    )

    if relative_to:
        import_dir = os.path.relpath(import_dir, relative_to)

    return import_dir
Exemplo n.º 37
0
def populate_sub_cache(ptask_version=None, refresh=False):

    if not ptask_version:

        ptask_area = PTaskArea.current()
        ptask = PTask.get(ptask_area.spec)

        if ptask_area.version:
            ptask_version = ptask.version(ptask_area.version)
        else:
            ptask_version = ptask.latest_version

    nuke_file = nuke.root().name()
    nuke_dir = os.path.dirname(nuke_file)

    if refresh or not SUBD_REPR_CACHE:

        for sub in ptask_version.subscriptions:
            for product_repr in sub.product_version.representations:

                product = product_repr.product_version.product

                if product.category != 'imgseq':
                    continue

                product_repr_str = product.name_spec + ' @ ' + \
                    product_repr.type

                if product_repr.resolution != 'none':
                    product_repr_str += PTaskSpec.SEPARATOR + \
                    product_repr.resolution 

                sub_import_dir = get_import_dir(product_repr,
                    product=product, area=ptask_area, relative_to=nuke_dir)

                # populate cache lookups
                SUBD_REPR_CACHE.append(product_repr)
                PRODUCT_REPR_STR_TO_PATH[product_repr_str] = \
                    sub_import_dir
Exemplo n.º 38
0
    def validate(self):
        
        use_cur_version = False

        if not isinstance(self.ptask, PTask):

            if not self.ptask or self.ptask == '.':
                use_cur_version = True

            cur_spec = PTaskArea.current().spec
            full_spec = PTaskSpec.get(self.ptask, relative_to=cur_spec)

            # try to get a ptask instance from the db
            try:
                ptask = PTask.get(full_spec)
            except PTaskError as e:
                # fall back to the input spec
                try:
                    ptask = PTask.get(self.spec)
                except PTaskError:
                    raise ActionError(
                        'Could not determine ptask from: "{s}"'.format(
                            s=self.spec)
                    )

            self._ptask = ptask

        latest_ver = self.ptask.latest_version

        if use_cur_version:
            cur_ptask_ver = DpaVars.ptask_version().get()
            if cur_ptask_ver and cur_ptask_ver != latest_ver.number:
                self._ptask_version = self.ptask.version(cur_ptask_ver)
                self._version = cur_ptask_ver
            else:
                self._ptask_version = self.ptask.latest_version
        else:
            self._ptask_version = self.ptask.latest_version
Exemplo n.º 39
0
    def log_action(self):

        if not self.__class__.logging:
            return

        # try to format the args/kwargs to be readable in the log
        args_str = ""
        if len(self.args):
            args_str += ", ".join([str(a) for a in self.args])
            args_str = "args(" + args_str + ")"
        if len(self.kwargs.keys()):
            kwargs_str = ", ".join(
                sorted([
                    k + '="' + str(v) + '"' for (k, v) in self.kwargs.items()
                    if v
                ]))
            args_str = args_str + " kwargs(" + kwargs_str + ")"

        msg = "({s})".format(s=PTaskArea.current().spec)
        msg += " " + args_str

        # log the action and its args
        self.logger.info(msg)
Exemplo n.º 40
0
    def __init__(self):

        self._ptask_area = PTaskArea.current()
        options_config = self._ptask_area.config(VERSION_OPTIONS_CONFIG,
                                                 composite_ancestors=True)

        try:
            self._ptask = PTask.get(self._ptask_area.spec)
        except PTaskError as e:
            error_dialog = QtGui.QErrorMessage(self)
            error_dialog.setWindowTitle('Version Failure')
            error_dialog.showMessage("Unable to determine current ptask.")
            return

        icon_path = IconFactory().disk_path(VERSION_ICON_URI)

        super(PTaskVersionDialog, self).__init__(
            title='Version up',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Submit',
            modal=False,
        )
Exemplo n.º 41
0
    def __init__(self):

        self._ptask_area = PTaskArea.current()
        options_config = self._ptask_area.config(VERSION_OPTIONS_CONFIG,
            composite_ancestors=True)

        try:
            self._ptask = PTask.get(self._ptask_area.spec)
        except PTaskError as e:
            error_dialog = QtGui.QErrorMessage(self)
            error_dialog.setWindowTitle('Version Failure')
            error_dialog.showMessage("Unable to determine current ptask.")
            return

        icon_path = IconFactory().disk_path(VERSION_ICON_URI)

        super(PTaskVersionDialog, self).__init__(
            title='Version up',
            options_config=options_config,
            icon_path=icon_path,
            action_button_text='Submit',
            modal=False,
        )
Exemplo n.º 42
0
    def validate(self):

        use_cur_version = False

        if not isinstance(self.ptask, PTask):

            if not self.ptask or self.ptask == '.':
                use_cur_version = True

            cur_spec = PTaskArea.current().spec
            full_spec = PTaskSpec.get(self.ptask, relative_to=cur_spec)

            # try to get a ptask instance from the db
            try:
                ptask = PTask.get(full_spec)
            except PTaskError as e:
                # fall back to the input spec
                try:
                    ptask = PTask.get(self.spec)
                except PTaskError:
                    raise ActionError(
                        'Could not determine ptask from: "{s}"'.format(
                            s=self.spec))

            self._ptask = ptask

        latest_ver = self.ptask.latest_version

        if use_cur_version:
            cur_ptask_ver = DpaVars.ptask_version().get()
            if cur_ptask_ver and cur_ptask_ver != latest_ver.number:
                self._ptask_version = self.ptask.version(cur_ptask_ver)
                self._version = cur_ptask_ver
            else:
                self._ptask_version = self.ptask.latest_version
        else:
            self._ptask_version = self.ptask.latest_version
Exemplo n.º 43
0
def _get_products(wild_spec):

    ptask_spec = PTaskArea.current().spec
    full_spec = PTaskSpec.get(wild_spec, relative_to=ptask_spec)

    if PTaskSpec.WILDCARD in full_spec:

        search_str = ",".join(
            filter(None,
                   full_spec.strip().split(PTaskSpec.WILDCARD)))

    # no wildcard, match all products under current location
    else:
        search_str = full_spec

    # XXX this is inefficient. need better filtering on the backend
    products = Product.list(search=search_str)

    matching_products = []

    # the rest api's search filter isn't that great. it doesn't maintain any
    # knowledge of order for the supplied filters. So, it will return products
    # that match all of the search terms, but not necessarily in the order
    # supplied. Do one more match against the returned products specs keeping
    # the order of the supplied wildcard spec.

    regex_spec = "^" + \
        full_spec.replace(PTaskSpec.WILDCARD, "([\w=]+)?") + "$"

    regex_spec = re.compile(regex_spec)

    for product in products:
        if regex_spec.match(product.spec):
            matching_products.append(product)

    return matching_products
Exemplo n.º 44
0
def _get_products(wild_spec):

    ptask_spec = PTaskArea.current().spec
    full_spec = PTaskSpec.get(wild_spec, relative_to=ptask_spec)

    if PTaskSpec.WILDCARD in full_spec:

        search_str = ",".join(
            filter(None, full_spec.strip().split(PTaskSpec.WILDCARD))
        )

    # no wildcard, match all products under current location
    else:
        search_str = full_spec

    # XXX this is inefficient. need better filtering on the backend
    products = Product.list(search=search_str)

    matching_products = []

    # the rest api's search filter isn't that great. it doesn't maintain any
    # knowledge of order for the supplied filters. So, it will return products
    # that match all of the search terms, but not necessarily in the order
    # supplied. Do one more match against the returned products specs keeping
    # the order of the supplied wildcard spec. 

    regex_spec = "^" + \
        full_spec.replace(PTaskSpec.WILDCARD, "([\w:]+)?") + "$"

    regex_spec = re.compile(regex_spec)

    for product in products:
        if regex_spec.match(product.spec):
            matching_products.append(product)

    return matching_products
Exemplo n.º 45
0
def load_toolbars():
    """Load all custom toolbars via config files."""

    ptask_area = PTaskArea.current()
    nuke_toolbar_config = ptask_area.config(config_file=NUKE_TOOLBAR_CONFIG,
                                            composite_ancestors=True)

    for (toolbar_name, toolbar_config) in nuke_toolbar_config.iteritems():

        toolbar = nuke.toolbar(toolbar_name)
        for (item_key, item_config) in toolbar_config.iteritems():

            name = item_config.get('label', item_key)
            command = item_config.get('command', "print 'No op'")
            icon = item_config.get('image', None)
            tooltip = item_config.get('annotation', "")

            if icon:
                icon = IconFactory().disk_path(icon)

            toolbar.addCommand(name=name,
                               command=command,
                               icon=icon,
                               tooltip=tooltip)
Exemplo n.º 46
0
    def setup_cl_args(cls, parser):

        parser.add_argument("spec",
                            nargs="?",
                            default=PTaskArea.current().spec,
                            help="The production task specification.")

        parser.add_argument("-s",
                            "--shell",
                            default=ShellFormatters.default().name,
                            choices=sorted(
                                [f.name for f in ShellFormatters.all()]),
                            help="Shell type env commands should target.")

        parser.add_argument("-p",
                            "--previous",
                            nargs="?",
                            const="list",
                            help="Choose a previous ptask env.")

        parser.add_argument("-v",
                            "--version",
                            type=int,
                            help="The version of the ptask to print info for.")
Exemplo n.º 47
0
    def validate(self):

        # validate the ptask
        if not isinstance(self._ptask, PTask):
            try:
                cur_spec = PTaskArea.current().spec
                full_spec = PTaskSpec.get(self._ptask, relative_to=cur_spec)
                self._ptask = PTask.get(full_spec)
            except PTaskError:
                raise ActionError("Could not determine ptask from: {p}".format(
                    p=self._ptask))

        # find the version of the ptask to update
        if isinstance(self._ptask_version, PTaskVersion):
            if not self._ptask_version.ptask_spec == self._ptask_spec:
                raise ActionError(
                    "Supplied ptask version doesn't match supplied ptask.")
        elif self._ptask_version:
            matches = PTaskVersion.list(
                ptask=self._ptask.spec, number=self._ptask_version
            )
            if len(matches) != 1:
                raise ActionError(
                    "Unable to find ptask '{p}' at version '{v}'".format(
                        p=self._ptask.spec, v=self._ptask_version
                    )
                )
            else:
                self._ptask_version = matches[0]
        else:
            self._ptask_version = self._ptask.latest_version

        # XXX rule
        
        # don't allow if ptask_version already has published products
        if self._ptask_version.published:
            raise ActionError(
                "Subscriptions can not be modified." + \
                "Version {v} of {p} has published products.".format(
                    v=self._ptask_version.number_padded, 
                    p=self._ptask.spec
                ))

        # XXX

        subs = [] 

        # valdiate the subscriptions to update
        if self._subs:

            # get explicit subs
            for sub in self._subs:

                if isinstance(sub, ProductSubscription):
                    subs_to_udpate.append(sub)
                    continue

                try:
                    sub = int(sub)
                except:
                    raise ActionError("Could not determine sub from: {s}".\
                        format(s=sub))
                else:
                    matches = ProductSubscription.list(id=sub)         
                    if len(matches) != 1:
                        raise ActionError("Unable to identify sub for id: " + \
                            str(sub))
                    else:
                        subs.append(matches[0])

        else:
            # all subs for ptask version
            subs.extend(self._ptask_version.subscriptions)

        self._subs = subs

        update_map = defaultdict(dict)

        for sub in subs:
            
            sub_product_ver = sub.product_version
            
            update_map[sub.id]['old'] = sub_product_ver

            if sub.locked:
                update_map[sub.id]['new'] = None
                update_map[sub.id]['note'] = 'Subscription locked'
                continue 

            if sub_product_ver.is_official:
                update_map[sub.id]['new'] = None
                update_map[sub.id]['note'] = 'Already subscribed to official'
                continue 

            sub_product = sub_product_ver.product

            official_ver = sub_product.official_version

            if official_ver and official_ver.number > sub_product_ver.number:
                update_map[sub.id]['new'] = official_ver
                update_map[sub.id]['note'] = 'Official version'
                continue 

            if sub.product_version.product.ptask.spec == self.ptask.spec:
                all_vers = [v for v in sub_product.versions]
            else:
                all_vers = [v for v in sub_product.versions if v.published]

            all_vers.sort(key=lambda v: v.number_padded)

            if all_vers:
                latest = all_vers[-1]
                if latest.number > sub_product_ver.number:
                    update_map[sub.id]['new'] = latest 
                    if latest.published:
                        update_map[sub.id]['note'] = 'Latest published version'
                    else:
                        update_map[sub.id]['note'] = 'Latest version'
                    continue 
                else:
                    update_map[sub.id]['new'] = None
                    if sub_product_ver.published:
                        update_map[sub.id]['note'] = \
                            'Already using latest published'
                    else:
                        update_map[sub.id]['note'] = 'Already using latest'
                    continue 
                    
            else:
                update_map[sub.id]['new'] = None
                update_map[sub.id]['note'] = 'No new versions'
                continue 

        self._update_map = update_map
Exemplo n.º 48
0
    def ptask_area(self):

        if not hasattr(self, '_ptask_area'):
            self._ptask_area = PTaskArea.current()

        return self._ptask_area
Exemplo n.º 49
0
    def _print_ptask_env(self):

        # remove any whitespace on the head/tail of the spec
        spec = self.spec.strip()
        ptask_area = None

        if self.version:
            spec = PTaskSpec.VERSION.join([spec, str(self.version)])
            

        replace_match = re.match("\.?/([=\w]+)/([=\w]+)/", spec)

        # handle 'none' as a valid spec - unset current ptask (set it to root)
        if spec.lower() == 'none':
            spec = ""
            full_spec = PTaskSpec.get(spec)
            try:
                ptask_area = PTaskArea(full_spec)
            except:
                pass

        # special character '-' indicates use the last set ptask spec
        elif spec == "-":
            ptask_area = PTaskArea.previous()

        # set to a similar ptask with text replacement
        elif replace_match:

            cur_area_spec = PTaskArea.current().spec
            repl_spec = cur_area_spec.replace(
                replace_match.group(1), replace_match.group(2))
            try:
                ptask_area = PTaskArea(repl_spec)
            except:
                pass
            
        # use the supplied spec relative to the current ptask
        else:

            relative_to = PTaskArea.current().spec

            while ptask_area is None:

                try:
                    full_spec = PTaskSpec.get(spec, relative_to=relative_to)
                except PTaskSpecError as e:
                    raise ActionError(str(e))

                try:
                    # if this is successful, we'll break out of the while
                    ptask_area = PTaskArea(full_spec)
                except PTaskAreaError as e: 
                    # no match, check the parent relative spec
                    relative_to = PTaskSpec.parent(relative_to)
                    # there is no parent, break out of the while
                    if relative_to is None:
                        break

        # dump out commands used for setting the environment for the supplied
        # spec.

        if not ptask_area:
            raise ActionError(
                "Could not determine ptask area from: " + str(spec), 
            )

        ptask = None

        # delay the db query to this point to prevent multiple, unnecessary db
        # queries. if we're at this point, we know there's at least a
        # corresponding directory on disk. 
        if ptask_area.base_spec:
            try:
                ptask = PTask.get(ptask_area.base_spec)
            except PTaskError as e:
                pass

        if not ptask and ptask_area.spec != "":
            raise ActionError("Could not determine ptask from: " + str(spec))
        
        ptask_area.set(shell=self.shell, ptask=ptask)
Exemplo n.º 50
0
def playblaster(quality, sequence, autoReview):
    #Does some error checking to ensure the fspattern is correct
    area = PTaskArea.current()
    spec = None
    if area:
        spec = area.spec
    else:
        print "You need to dpaset into a ptask to use this tool."
        return False
    currentCam = cmds.modelPanel(cmds.getPanel(wf=True), q=True, cam=True)
    currentCamMunged = currentCam.replace('|', '_')
    focalLength = cmds.camera(currentCam, q=True, fl=True)
    cameraName = currentCamMunged.title() + "Fov" + str(focalLength)
    print "Camera Name: " + cameraName
    specName = spec.name(spec).title()

    if not autoReview:
        playblastdir = "/scratch" + area.dir()
        #listing = os.listdir(playblastdir)
        print "Making directory " + playblastdir
        os.system("mkdir -p " + playblastdir)
        #get a listing of the version numbers in the directory
        nbversions = len(os.listdir(playblastdir))
        versionFrame = "%04d" % (nbversions + 1)
        fileName = "%s/playblast%s%s-%s" % (playblastdir, specName, cameraName,
                                            versionFrame)
        print "writing playblast to file " + fileName + ".mov"
        xVal = cmds.getAttr('defaultResolution.width')
        yVal = cmds.getAttr('defaultResolution.height')
        if sequence:
            sqMgr = cmds.listConnections('sequenceManager1', s=True,
                                         d=False)[0]
            seqEnd = cmds.getAttr(str(sqMgr) + ".maxFrame")
            seqStart = cmds.getAttr(str(sqMgr) + ".minFrame")
            print "SqStart: " + str(seqStart)
            print "SqEnd: " + str(seqEnd)
            cmds.playblast(startTime=seqStart,
                           endTime=seqEnd,
                           sequenceTime=sequence,
                           f=fileName,
                           percent=quality,
                           offScreen=True,
                           format="qt",
                           width=xVal,
                           height=yVal)
        else:
            cmds.playblast(f=fileName,
                           percent=quality,
                           offScreen=True,
                           format="qt",
                           width=xVal,
                           height=yVal)
        cmds.deleteUI("PBQuality")
        os.chmod(fileName + ".mov", 0777)
        os.system("vlc " + fileName + ".mov &")
        return True
    if autoReview:
        #create a product to put this in
        xVal = cmds.getAttr('defaultResolution.width')
        yVal = cmds.getAttr('defaultResolution.height')
        product_spec = "playblast=movie"
        product_type = "mov"
        product_resolution = str(xVal) + "x" + str(yVal)
        product_description = "auto generated in dpa playblast tool"
        from dpa.action.registry import ActionRegistry
        create_action_cls = ActionRegistry().get_action('create', 'product')
        create_action = create_action_cls(product=product_spec,
                                          ptask=spec,
                                          description=product_description,
                                          file_type=product_type,
                                          resolution=product_resolution)
        try:
            create_action()
        except ActionError as e:
            raise EntityError("Unable to create a product: " + str(e))

        #use product to get the directory path
        area = create_action.product_repr.area
        playblastdir = area.dir()
        versionFrame = create_action.product_version.number_padded
        baseFileName = "playblast%s%s-%s" % (specName, cameraName,
                                             versionFrame)
        fileName = playblastdir + "/" + baseFileName
        print "writing playblast to file " + fileName + ".mov"
        if sequence:
            sqMgr = cmds.listConnections('sequenceManager1', s=True,
                                         d=False)[0]
            seqEnd = cmds.getAttr(str(sqMgr) + ".maxFrame")
            seqStart = cmds.getAttr(str(sqMgr) + ".minFrame")
            print "SqStart: " + str(seqStart)
            print "SqEnd: " + str(seqEnd)
            cmds.playblast(startTime=seqStart,
                           endTime=seqEnd,
                           sequenceTime=sequence,
                           f=fileName,
                           percent=quality,
                           offScreen=True,
                           format="qt",
                           width=xVal,
                           height=yVal)
        else:
            cmds.playblast(f=fileName,
                           percent=quality,
                           offScreen=True,
                           format="qt",
                           width=xVal,
                           height=yVal)
        cmds.deleteUI("PBQuality")
        os.chmod(fileName + ".mov", 0777)
        reviewcmd = "cd " + playblastdir + "; dpacreatereview " + baseFileName + ".mov " + str(
            create_action.product_repr.spec)
        print "creating review: " + reviewcmd
        os.system(reviewcmd)
        os.system("vlc " + fileName + ".mov &")
        return True

    cmds.error("Invalid selections.")
    return False
Exemplo n.º 51
0
def _get_url_config():
    from dpa.ptask.area import PTaskArea
    return PTaskArea.current().config(
        URL_CONFIG_PATH,
        composite_ancestors=True,
    )
Exemplo n.º 52
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        product = None
        if full_spec:
            try:
                product = Product.get(full_spec)
            except ProductError as e:
                # fall back to input spec
                try:
                    product = Product.get(self.spec)
                except ProductError:
                    raise ActionError(
                        'Could not determine product from: "{s}"'.format(
                            s=self.spec
                        )
                    )
        if product:
            self._product = product
        else:
            raise ActionError(
                'Could not determine product from: "{s}"'.format(
                    s=self.spec
                )
            )

        if self.publish:
            vers = self._nums_to_versions(self.publish)
            self._publish = [v for v in vers if not v.published]

        if self.unpublish:
            vers = self._nums_to_versions(self.unpublish)
            self._unpublish = [v for v in vers if v.unpublish]

        if self.deprecate:
            vers = self._nums_to_versions(self.deprecate)
            self._deprecate = [v for v in vers if not v.deprecated]

        if self.undeprecate:
            vers = self._nums_to_versions(self.undeprecate)
            self._undeprecate = [v for v in vers if v.deprecated]

        if self.official:
            vers = self._nums_to_versions(self.official)
            if len(vers) > 1:
                raise ActionError("Can't official more than one version.")
            to_official = vers[0]
            if to_official.number == self.product.official_version_number:
                raise ActionError(
                    "Version {v} of '{p}' is already official.".format(
                        v=to_official.number,
                        p=self.product.spec,
                    )
                )
            if not to_official.published:
                if not self.publish:
                    self._publish = [to_official]
                else:
                    self._publish.append(to_official)
            self._official = to_official

        if self.publish and self.unpublish:
            overlap = set([v.spec for v in self.publish]).intersection(
                set([v.spec for v in self.unpublish]))
            if len(overlap) > 0:
                raise ActionError(
                    "Can't publish and unpublish the same versions.")

        if self.deprecate and self.undeprecate:
            overlap = set([v.spec for v in self.deprecate]).intersection(
                set([v.spec for v in self.undeprecate]))
            if len(overlap) > 0:
                raise ActionError(
                    "Can't deprecate and undeprecate the same versions.")

        # XXX publish if not already when officialing
        # XXX can't official a deprecated version
        # XXX can't deprecate the official version
        # XXX can't unpublish something that has subscribers
        # XXX add active to subscription model

        if (self.publish is None and 
            self.unpublish is None and
            self.deprecate is None and
            self.undeprecate is None and
            self.official is None and
            self.noofficial is False):
            raise ActionError("No actions to perform.")
Exemplo n.º 53
0
    def validate(self):

        cur_spec = PTaskArea.current().spec
        full_spec = PTaskSpec.get(self.spec, relative_to=cur_spec)

        product = None
        if full_spec:
            try:
                product = Product.get(full_spec)
            except ProductError as e:
                # fall back to input spec
                try:
                    product = Product.get(self.spec)
                except ProductError:
                    raise ActionError(
                        'Could not determine product from: "{s}"'.format(
                            s=self.spec
                        )
                    )
        if product:
            self._product = product
        else:
            raise ActionError(
                'Could not determine product from: "{s}"'.format(
                    s=self.spec
                )
            )

        if self.publish:
            vers = self._nums_to_versions(self.publish)
            self._publish = [v for v in vers if not v.published]

        if self.unpublish:
            vers = self._nums_to_versions(self.unpublish)
            self._unpublish = [v for v in vers if v.unpublish]

        if self.deprecate:
            vers = self._nums_to_versions(self.deprecate)
            self._deprecate = [v for v in vers if not v.deprecated]

        if self.undeprecate:
            vers = self._nums_to_versions(self.undeprecate)
            self._undeprecate = [v for v in vers if v.deprecated]

        if self.official:
            vers = self._nums_to_versions(self.official)
            if len(vers) > 1:
                raise ActionError("Can't official more than one version.")
            to_official = vers[0]
            if to_official.number == self.product.official_version_number:
                raise ActionError(
                    "Version {v} of '{p}' is already official.".format(
                        v=to_official.number,
                        p=self.product.spec,
                    )
                )
            if not to_official.published:
                if not self.publish:
                    self._publish = [to_official]
                else:
                    self._publish.append(to_official)
            self._official = to_official

        if self.publish and self.unpublish:
            overlap = set([v.spec for v in self.publish]).intersection(
                set([v.spec for v in self.unpublish]))
            if len(overlap) > 0:
                raise ActionError(
                    "Can't publish and unpublish the same versions.")

        if self.deprecate and self.undeprecate:
            overlap = set([v.spec for v in self.deprecate]).intersection(
                set([v.spec for v in self.undeprecate]))
            if len(overlap) > 0:
                raise ActionError(
                    "Can't deprecate and undeprecate the same versions.")

        # XXX publish if not already when officialing
        # XXX can't official a deprecated version
        # XXX can't deprecate the official version
        # XXX can't unpublish something that has subscribers
        # XXX add active to subscription model

        if (self.publish is None and 
            self.unpublish is None and
            self.deprecate is None and
            self.undeprecate is None and
            self.official is None and
            self.noofficial is False):
            raise ActionError("No actions to perform.")
Exemplo n.º 54
0
    def _output_options(self):

        output_type_lbl = QtGui.QLabel("Output:")
        output_type = QtGui.QComboBox()
        output_type.addItems(['Automatic', 'Manual'])

        header_layout = QtGui.QHBoxLayout()
        header_layout.addStretch()
        header_layout.addWidget(output_type_lbl)
        header_layout.addWidget(output_type)
        header_layout.addStretch()

        # ---- auto

        cur_area = PTaskArea.current()
        self._cur_ptask = PTask.get(cur_area.spec)
        if self._cur_ptask:
            self._version = \
                cur_area.version or self._cur_ptask.latest_version.number
        else:
            self._cur_ptask = None
            self._version = "None"

        ptask_lbl = QtGui.QLabel("PTask:")
        ptask_edit = QtGui.QLineEdit(str(self._cur_ptask))
        ptask_edit.setReadOnly(True)

        version_num = QtGui.QLabel("<B>v" + str(self._version) + "</B>")

        auto_layout = QtGui.QGridLayout()
        auto_layout.addWidget(ptask_lbl, 0, 0, QtCore.Qt.AlignRight)
        auto_layout.addWidget(ptask_edit, 0, 1)
        auto_layout.addWidget(version_num, 0, 2, QtCore.Qt.AlignLeft)
        auto_layout.setColumnStretch(0, 0)
        auto_layout.setColumnStretch(1, 1000)

        auto_widgets = QtGui.QWidget()
        auto_widgets.setLayout(auto_layout)

        # ---- manual

        dir_lbl = QtGui.QLabel("Directory:")
        self._dir_edit = QtGui.QLineEdit(os.getcwd())

        dir_btn = QtGui.QPushButton()
        dir_btn.setFlat(True)
        dir_btn_size = QtCore.QSize(22, 22)
        dir_btn.setFixedSize(dir_btn_size)
        dir_btn.setIcon(QtGui.QIcon(self.__class__._dir_path))
        dir_btn.setIconSize(dir_btn_size)

        dir_dialog = QtGui.QFileDialog(self, 'Output directory', 
            os.getcwd())
        dir_dialog.setFileMode(QtGui.QFileDialog.Directory)
        dir_dialog.setOption(QtGui.QFileDialog.ShowDirsOnly, True)
        dir_dialog.setOption(QtGui.QFileDialog.DontResolveSymlinks, True)
        dir_dialog.setOption(QtGui.QFileDialog.HideNameFilterDetails, True)
        dir_dialog.fileSelected.connect(self._dir_edit.setText)

        dir_btn.clicked.connect(dir_dialog.show)

        manual_layout = QtGui.QGridLayout()
        manual_layout.setContentsMargins(0, 0, 0, 0)
        manual_layout.addWidget(dir_lbl, 0, 0, QtCore.Qt.AlignRight)
        manual_layout.addWidget(self._dir_edit, 0, 1)
        manual_layout.addWidget(dir_btn, 0, 2)
        manual_layout.setColumnStretch(0, 0)
        manual_layout.setColumnStretch(1, 1000)
        manual_layout.setColumnStretch(2, 0)

        manual_widgets = QtGui.QWidget()
        manual_widgets.setLayout(manual_layout)

        self._output_stack = QtGui.QStackedWidget()
        self._output_stack.addWidget(auto_widgets)
        self._output_stack.addWidget(manual_widgets)

        output_type.activated.connect(self._output_stack.setCurrentIndex)

        # ---- layout

        output_layout = QtGui.QVBoxLayout()
        output_layout.addLayout(header_layout)
        output_layout.addWidget(self._output_stack)

        return output_layout