def validate(self): try: self._sub_id = int(self._sub_id) except ValueError: raise ActionError("Invalid subscription id.") # make sure subscription exists matches = ProductSubscription.list(id=self._sub_id) if len(matches) != 1: raise ActionError( "Unable to identify subscription for id: " + str(self._sub_id) ) self._subscription = matches[0] # make sure subsription is not locked if self._subscription.locked: raise ActionError("Can't remove locked subscription.") # make sure ptask version has no published products if self._subscription.ptask_version.published: raise ActionError( "Can't modify subscriptions. " + \ "The ptask version has published products." )
def _create_ptask(self): parent = PTaskSpec.parent(self.spec) name = PTaskSpec.name(self.spec) # create if not self.ptask: try: self.logger.debug("Creating ptask: " + str(self.spec)) self._ptask = PTask.create( name, self.ptask_type, self.description, creator_username=self.creator, parent_spec=parent, start_date=str(self.start_date), due_date=str(self.due_date), ) except PTaskError as e: raise ActionError("Failed to create ptask: " + str(e)) # update else: try: self.logger.debug("Updating ptask: " + str(self.spec)) self.ptask.update( description=self.description, start_date=str(self.start_date), due_date=str(self.due_date), ) except PTaskError as e: raise ActionError("Failed to update ptask: " + str(e))
def _ids_to_subs(self, sub_ids): subs = [] if not sub_ids: return subs for sub_id in sub_ids: if isinstance(sub_id, ProductSubscription): subs.append(sub_id) continue try: sub = int(sub_id) except: raise ActionError("Could not determine sub from: {s}".\ format(s=sub_id)) else: matches = ProductSubscription.list(id=sub_id) if len(matches) != 1: raise ActionError("Unable to identify sub for id: " + \ str(sub_id)) else: subs.append(matches[0]) return subs
def _create_version(self): new_version = self.ptask.next_version_number location_code = current_location_code() try: self._new_ptask_version = PTaskVersion.create( current_username(), "in progress...".format(n=new_version), location_code, ptask_spec=self.ptask.spec, number=new_version, parent_spec=self.source_version.spec, ) except PTaskVersionError as e: raise ActionError("Failed to create ptask version: " + str(e)) else: print "\nNew version successfully created in the database." # ---- provision a version directory in the ptask area try: self.ptask.area.provision( self.ptask.area.dir(version=new_version, verify=False) ) except PTaskAreaError as e: raise ActionError("Unable to provision version directory.") else: print "\nSuccessfully provisioned directory for version: " + \ str(new_version)
def _link_sub(self, sub, app): area = PTaskArea(self.ptask.spec, version=self.version) product_ver = sub.product_version try: product_ver_area = PTaskArea(product_ver.spec) except PTaskAreaError as e: raise ActionError("Unable to locate product directory for: " + product_ver.spec) product_ver_path = product_ver_area.path product = product_ver.product product_ver_import_dir = os.path.join('import', app, product.name) try: area.provision(product_ver_import_dir) except PTaskAreaError as e: raise ActionError("Failed to provision product import dir: " + str(e)) link_name = os.path.join(area.path, product_ver_import_dir, product.category) print "Creating subscription {a} link for: {pv}".format( a=app, pv=product_ver.spec) os.symlink(product_ver_path, link_name) product_ver_area = PTaskArea(product_ver.spec)
def execute(self): try: ProductSubscription.delete( self.subscription.ptask_version_spec, self.subscription.product_version_spec, ) except ProductSubscriptionError as e: raise ActionError("Subscription removal failed: " + str(e)) else: if self.interactive: print "\nSubscription removed.\n" if self._no_refresh: return # refresh the subscriptions on disk refresh_action_cls = ActionRegistry().get_action('refresh', 'subs') if not refresh_action_cls: raise ActionError("Could not find sub refresh action.") try: refresh_action = refresh_action_cls( self.subscription.ptask_version.ptask) refresh_action.interactive = False refresh_action() except ActionError as e: raise ActionError("Failed to refresh subs on disk: " + str(e))
def __init__(self, spec, ptask_type=None, description=None, creator=None, start_date=None, due_date=None, source=None, force=True): super(PTaskCreateAction, self).__init__( spec, ptask_type=ptask_type, description=description, creator=creator, start_date=start_date, due_date=due_date, source=source, force=force, ) # allow calling code to override the target to specify the ptask type # to create if ptask_type is None: if self.__class__.target_type is not 'ptask': ptask_type = self.__class__.target_type else: raise ActionError("PTask type is required.") # do some initial validation on the supplied spec parent = PTaskSpec.parent(spec) if parent != "": try: parent = PTask.get(parent) except PTaskError: raise ActionError("Parent ptask does not exist: " + parent) name = PTaskSpec.name(spec) try: name = validate_ptask_name(name) except PTaskError as e: raise ActionError("Invalid ptask name: " + str(e)) # input self._spec = spec self._ptask_type = ptask_type self._description = description self._creator = creator self._start_date = start_date self._due_date = due_date self._source = source self._force = force # to create self._ptask = None self._ptask_area = None self._ptask_version = None
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, )
def _source_another_ptask(self): source_action_class = ActionRegistry().get_action('source', 'ptask') if not source_action_class: raise ActionError("Could not find ptask source action.") try: source_action = source_action_class( source=self.source, destination=self.ptask, force=True, ) source_action.interactive = False source_action() except ActionError as e: raise ActionError("Failed to source ptask: " + str(e)) exceptions = [] # copy the subscriptions from the source ptask self._source_subs(self.source, self.ptask) # recursively create child ptasks from the source for source_child in self.source.children: try: child_spec = \ self.ptask.spec + PTaskSpec.SEPARATOR + source_child.name child_create = PTaskCreateAction( child_spec, ptask_type=source_child.type, description="Sourced from: " + source_child.spec, creator=self.creator, start_date=self.start_date, due_date=self.due_date, source=source_child, force=True, ) child_create.interactive = False child_create() except ActionError as e: exceptions.append(e) if exceptions: msg = "\n".join([str(e) for e in exceptions]) raise ActionError("Problem sourcing: " + self.source.spec + "\n\n" + msg)
def _create_status(self): existing = ProductRepresentationStatus.list( product_representation=self._product_repr.spec, location=current_location_code(), ) if len(existing) == 1: self._product_repr_status = existing.pop() if self.interactive: print "\nProduct representation status exists: " + \ Style.bright + self._product_repr_status.spec + Style.reset else: try: self._product_repr_status = ProductRepresentationStatus.create( product_representation=self._product_repr.spec, location=current_location_code(), status=1, ) except ProductRepresentationStatusError as e: raise ActionError( "Unable to create product representation status: " + str(e)) else: if self.interactive: print "\nCreated product representation status: " + \ Style.bright + self._product_repr_status.spec + \ Style.reset
def _create_area(self): try: self._product_area = PTaskArea.create(self.product_repr) except PTaskAreaError as e: raise ActionError( "Unable to create product area on disk: " + str(e))
def _create_product(self): existing = Product.list( name=self._name, category=self._category, ptask=self._ptask.spec, ) if len(existing) == 1: self._product = existing.pop() self._product.update(description=self._description) if self.interactive: print "\nBase product exists: " + \ Style.bright + self._product.spec + Style.reset else: try: self._product = Product.create( ptask=self._ptask.spec, name=self._name, category=self._category, description=self._description, creator=current_username(), ) except ProductError as e: raise ActionError("Unable to create product: " + str(e)) else: if self.interactive: print "\nCreated base product: " + \ Style.bright + self._product.spec + Style.reset
def _get_ptask_spec_from_history(self): # allow selection via history list try: self.spec = self._get_ptask_spec_history()[int(self.previous)] except Exception as e: raise ActionError("Invalid ptask history index.")
def _copy_subs(self): if self.interactive: print "\nCopying forward subscriptions:" ptask_version_spec = self.new_ptask_version exceptions = [] for sub in self.source_version.subscriptions: try: new_sub = ProductSubscription.create( ptask_version_spec, sub.product_version_spec, ) except ProductSubscriptionError as e: exceptions.append((sub, e)) else: print " " + Style.bright + \ str(sub.product_version_spec) + Style.normal if exceptions: msgs = [] for (sub, e) in exceptions: msgs.append(sub.product_version_spec + ": " + str(e)) raise ActionError( "Unable to copy forward some subscriptions:\n\n" + \ "\n".join(msgs) )
def _create_version(self): existing = ProductVersion.list( ptask_version=self._ptask_version.spec, product=self._product.spec, ) if len(existing) == 1: self._product_version = existing.pop() self._product_version.update(release_note=self._note) if self.interactive: print "\nProduct version exists: " + \ Style.bright + self._product_version.spec + Style.reset else: try: self._product_version = ProductVersion.create( ptask_version=self._ptask_version.spec, product=self._product.spec, release_note=self._note, creator=current_username(), ) except ProductVersionError as e: raise ActionError("Unable to create product version: " + str(e)) else: if self.interactive: print "\nCreated product version: " + \ Style.bright + self._product_version.spec + Style.reset
def _refresh_subs(self): if self.interactive: print "\nRefreshing subscriptions." # refresh the subscriptions on disk refresh_action_cls = ActionRegistry().get_action('refresh', 'subs') if not refresh_action_cls: raise ActionError("Could not find sub refresh action.") try: refresh_action = refresh_action_cls(self.ptask) refresh_action.interactive = False refresh_action() except ActionError as e: raise ActionError("Failed to refresh subs on disk: " + str(e))
def _create_representation(self): existing = ProductRepresentation.list( product_version=self._product_version.spec, resolution=self._resolution, representation_type=self._file_type, ) if len(existing) == 1: self._product_repr = existing.pop() if self.interactive: print "\nProduct representation exists: " + \ Style.bright + self._product_repr.spec + Style.reset else: try: self._product_repr = ProductRepresentation.create( product_version=self._product_version.spec, resolution=self._resolution, representation_type=self._file_type, creation_location=current_location_code(), creator=current_username(), ) except ProductRepresentationError as e: raise ActionError( "Unable to create product representation: " + str(e)) else: if self.interactive: print "\nCreated product representation: " + \ Style.bright + self._product_repr.spec + Style.reset
def execute(self): # ---- get the actions we need create_action_cls = ActionRegistry().get_action('create', 'sub') if not create_action_cls: raise ActionError("Could not find create sub action.") refresh_action_cls = ActionRegistry().get_action('refresh', 'subs') if not refresh_action_cls: raise ActionError("Could not find sub refresh action.") # ---- use the create sub action to create/replace the subs errors = [] for sub in self.subs_to_source: product_version = sub.product_version product = product_version.product try: create_action = create_action_cls( product=product, ptask=self.current_ptask, version=product_version, ptask_version=self.current_ptask_version, no_refresh=True) create_action.interactive = False create_action() except ActionError as e: errors.append(e) # ---- refresh the subs' import dirs try: refresh_action = refresh_action_cls(self.current_ptask) refresh_action.interactive = False refresh_action() except ActionError as e: raise ActionError("Failed to refresh subs on disk: " + str(e)) # ---- spit some errors if need be if errors: raise ActionError("Errors occurred during source:\n" + \ "\n ".join([str(e) for e in errors]))
def _parse_product(self): # split the supplied product string to determine additional parts. # this sets unknown values to None (name, cat, ver, file_type, res) = list( self._product.split(PTaskSpec.SEPARATOR, 5) + [None] * 5 )[0:5] # name self._name = name # category if cat: if self._category and self._category != cat: raise ActionError( "Different categories specified: {c1} & {c2}".format( c1=self._category, c2=cat)) self._category = cat # version if ver: try: ver = int(ver) except ValueError: raise ActionError("Invalid version specified.") if self._version and self._version != ver: raise ActionError( "Different versions specified: {v1} & {v2}".format( v1=self._version, v2=ver)) self._version = ver # file_type if file_type: if self._file_type and self._file_type != file_type: raise ActionError( "Different file types specified: {t1} & {t2}".format( t1=self._file_type, t2=file_type)) self._file_type = file_type # resolution if res: if self._resolution and self._resolution != res: raise ActionError( "Different resolutions specified: {r1} & {r2}".format( r1=self._resolution, c2=res)) self._resolution = res
def _create_ptask_area(self): # ---- create the directory path if it doesn't exist try: self._ptask_area = PTaskArea(self.ptask.spec) except PTaskAreaError: pass else: if not self.force: raise ActionError("PTask area already exists.") if not self.ptask_area: try: self._ptask_area = PTaskArea.create(self.ptask) except PTaskAreaError as e: raise ActionError("Failed to create ptask area: " + str(e))
def validate(self): if not self._lock and not self._unlock: raise ActionError( "Must supply an action to perform (lock, unlock, etc.)") self._lock = self._ids_to_subs(self._lock) self._unlock = self._ids_to_subs(self._unlock)
def _get_path(self, ptask, version=None, latest_version=None, directory=None, location_override=None): cur_loc_code = current_location_code() if version: version_num = version.number else: if not latest_version: latest_version = ptask.latest_version version = latest_version version_num = None if location_override: loc_code = location_override.code else: loc_code = version.location_code if loc_code == cur_loc_code: try: path = ptask.area.dir( version=version_num, dir_name=directory, ) except PTaskAreaError: raise ActionError( "Path for 's' does not exist.".format(s=ptask.spec), ) path += "/" else: location = version.location if not location.host: raise ActionError( "Unable to sync with location '{l}'. Unknown host.".\ format(l=location.name) ) path = ptask.area.dir( version=version_num, dir_name=directory, root=location.filesystem_root, verify=False, ) path = current_username() + "@" + location.host + ":" + path + "/" return path
def _source_subs(self, source_ptask, dest_ptask): if self.interactive: print "\nSourcing subscriptions:" dest_ptask_version_spec = dest_ptask.latest_version.spec exceptions = [] for sub in source_ptask.latest_version.subscriptions: try: new_sub = ProductSubscription.create( dest_ptask_version_spec, sub.product_version_spec, ) except ProductSubscriptionError as e: exceptions.append((sub, e)) else: print " " + Style.bright + \ str(sub.product_version_spec) + Style.normal if exceptions: msgs = [] for (sub, e) in exceptions: msgs.append(sub.product_version_spec + ": " + str(e)) raise ActionError( "Unable to copy forward some subscriptions:\n\n" + \ "\n".join(msgs) ) else: # build the import directory... if self.interactive: print "\nRefreshing subscriptions." # refresh the subscriptions on disk refresh_action_cls = ActionRegistry().get_action('refresh', 'subs') if not refresh_action_cls: raise ActionError("Could not find sub refresh action.") try: refresh_action = refresh_action_cls(dest_ptask) refresh_action.interactive = False refresh_action() except ActionError as e: raise ActionError("Failed to refresh subs on disk: " + str(e))
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
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.")
def validate(self): if self.source: try: self._source = PTask.get(self.source) except PTaskError: raise ActionError( "Unable to retrieve ptask from source argument: " + \ str(self.source), )
def _sync_path(self): if self._product_version.published: raise ActionError( "Product version is already published at this version. Can " + \ "not overwrite: " + self._product_version.spec) if not self._path: return sync = SyncAction( source=self._path, destination=self._product_area.path, ) try: sync() except ActionError as e: raise ActionError("Failed to sync product source: " + str(e))
def _sync_latest_remote(self): # sync the local work directory with the contents of the remote work # directory (excluding products and child directories) source_action_class = ActionRegistry().get_action('sync', 'ptask') if not source_action_class: raise ActionError("Could not find ptask source action.") try: source_action = source_action_class( ptask=self.ptask, version="latest", force=True, ) source_action.interactive = False source_action() except ActionError as e: raise ActionError("Failed to sync the remote work directory.")
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))
def validate(self): try: location = Location.get(self.code) except LocationError as e: raise ActionError( 'Could not determine location from code: "{c}"'.\ format(c=self.code) ) self._location = location