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 _complete(self, spec, relative_to=None): in_spec = self.spec.strip().strip(PTaskSpec.SEPARATOR) full_spec = PTaskSpec.get(in_spec, relative_to=relative_to) ptask_area = None # is the supplied spec a ptask area? if so, print sub directories # if not, get the parent spec and print its sub directories try: ptask_area = PTaskArea(full_spec) except PTaskAreaError: in_spec = PTaskSpec.parent(in_spec) full_spec = PTaskSpec.parent(full_spec) try: ptask_area = PTaskArea(full_spec) except PTaskAreaError: pass if not ptask_area: return # append the child name to the input spec and print them out for completion match_specs = [] for area_dir in ptask_area.dirs(children=True, product_dirs=True): if in_spec: match_specs.append(in_spec + PTaskSpec.SEPARATOR + area_dir) else: match_specs.append(area_dir) return [m + PTaskSpec.SEPARATOR for m in match_specs]
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 get(cls, ptask_version_spec, product_version_spec, relative_to=None): # XXX PTaskSpec >> ContextSpec # XXX PTaskArea >> ContextArea # XXX PTaskEnv >> ContextEnv if not isinstance(ptask_version_spec, PTaskSpec): ptask_version_spec = PTaskSpec.get(ptask_version_spec, relative_to=relative_to) if not isinstance(product_version_spec, PTaskSpec): product_version_spec = PTaskSpec.get(product_version_spec, relative_to=relative_to) spec = ",".join([ptask_version_spec, product_version_spec]) return super(ProductSubscription, cls).get(spec)
def get(cls, ptask_version_spec, product_version_spec, relative_to=None): # XXX PTaskSpec >> ContextSpec # XXX PTaskArea >> ContextArea # XXX PTaskEnv >> ContextEnv if not isinstance(ptask_version_spec, PTaskSpec): ptask_version_spec = PTaskSpec.get( ptask_version_spec, relative_to=relative_to) if not isinstance(product_version_spec, PTaskSpec): product_version_spec = PTaskSpec.get( product_version_spec, relative_to=relative_to) spec = ",".join([ptask_version_spec, product_version_spec]) return super(ProductSubscription, cls).get(spec)
def children(self): child_ptasks = [] for child_dir in self.dirs(children=True): child_spec = PTaskSpec.get(child_dir, relative_to=self.spec) child_ptasks.append(PTaskArea(child_spec)) return child_ptasks
def current(cls): env = PTaskEnv.current() spec = PTaskSpec.get(env.ptask_spec.value) version = env.ptask_version.value try: return cls(spec, validate=False, version=version) except PTaskAreaError: return cls("")
def from_directory(cls, directory, validate=True, version=None): try: spec = PTaskSpec.from_directory(directory) except PTaskSpecError as e: raise PTaskAreaError("Unable to determine spec from directory.") return cls(spec, validate=validate, version=version)
def get_default_product_name(): name = "Comp" ptask_area = PTaskArea.current() if ptask_area: name = PTaskSpec.name(ptask_area.spec) + name return name
def siblings(self): parent_spec = PTaskSpec.parent(self.spec) try: parent_area = PTaskArea(parent_spec) except PTaskAreaError: return [] return [c for c in parent_area.children if c.spec != self.spec]
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 __init__(self, spec, validate=True, version=None): super(PTaskArea, self).__init__() # should be a fully qualified ptask spec if not isinstance(spec, PTaskSpec): spec = PTaskSpec.get(spec) ver_sep = PTaskSpec.VERSION if ver_sep in spec: if spec.count(ver_sep) > 1: raise PTaskAreaError("Multiple version specs unsupported.") (spec, version) = spec.split(ver_sep) spec = PTaskSpec.get(spec) # XXX this is making assumptions about a 1:1 correspondence # between filesystem directories and ptask specs. this may not always # be the case. need to consider cases where the ptasks in the hierarchy # are spread across production disks for various reasons. at least this # is isolated to this class and the API should remain the same. self._spec = spec self._version = version self._base_spec = spec.base_spec self._product_spec = spec.product_spec if self._version and self._product_spec: raise PTaskAreaError( "PTask version not supported with product area initialization." ) self._fs_root = DpaVars.filesystem_root().get() self._root = DpaVars.projects_root().get() self._base = os.path.join(*spec.split(PTaskSpec.SEPARATOR)) if self._version: self._base = os.path.join(self._base, '.' + str(version).zfill(4)) self._path = os.path.join(self._root, self._base) self._ancestor_paths = None if validate and not self.exists(): raise PTaskAreaError("PTaskArea does not exist.")
def __init__(self, spec, validate=True, version=None): super(PTaskArea, self).__init__() # should be a fully qualified ptask spec if not isinstance(spec, PTaskSpec): spec = PTaskSpec.get(spec) ver_sep = PTaskSpec.VERSION if ver_sep in spec: if spec.count(ver_sep) > 1: raise PTaskAreaError("Multiple version specs unsupported.") (spec, version) = spec.split(ver_sep) spec = PTaskSpec.get(spec) # XXX this is making assumptions about a 1:1 correspondence # between filesystem directories and ptask specs. this may not always # be the case. need to consider cases where the ptasks in the hierarchy # are spread across production disks for various reasons. at least this # is isolated to this class and the API should remain the same. self._spec = spec self._version = version self._base_spec = spec.base_spec self._product_spec = spec.product_spec if self._version and self._product_spec: raise PTaskAreaError( "PTask version not supported with product area initialization.") self._fs_root = DpaVars.filesystem_root().get() self._root = DpaVars.projects_root().get() self._base = os.path.join(*spec.split(PTaskSpec.SEPARATOR)) if self._version: self._base = os.path.join(self._base, '.' + str(version).zfill(4)) self._path = os.path.join(self._root, self._base) self._ancestor_paths = None if validate and not self.exists(): raise PTaskAreaError("PTaskArea does not exist.")
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)
def get(cls, product_representation_spec, location_spec, relative_to=None): # XXX PTaskSpec >> ContextSpec # XXX PTaskArea >> ContextArea # XXX PTaskEnv >> ContextEnv if not isinstance(product_representation_spec, PTaskSpec): product_representation_spec = PTaskSpec.get(product_representation_spec, relative_to=relative_to) spec = ",".join([product_representation_spec, location_spec]) return super(ProductRepresentationStatus, cls).get(spec)
def get(cls, product_representation_spec, location_spec, relative_to=None): # XXX PTaskSpec >> ContextSpec # XXX PTaskArea >> ContextArea # XXX PTaskEnv >> ContextEnv if not isinstance(product_representation_spec, PTaskSpec): product_representation_spec = PTaskSpec.get( product_representation_spec, relative_to=relative_to) spec = ",".join([product_representation_spec, location_spec]) return super(ProductRepresentationStatus, cls).get(spec)
def get(cls, spec, relative_to=None): # convenience that allows calling code to not have to type check # input that allows either spec or ptask if isinstance(spec, ProductVersion): return spec # XXX PTaskSpec >> ContextSpec # XXX PTaskArea >> ContextArea # XXX PTaskEnv >> ContextEnv if not isinstance(spec, PTaskSpec): spec = PTaskSpec.get(spec, relative_to=relative_to) return super(ProductVersion, cls).get(spec)
def get(cls, spec, relative_to=None): # convenience that allows calling code to not have to type check # input that allows either spec or ptask if isinstance(spec, Product): return spec # XXX PTaskSpec >> ContextSpec # XXX PTaskArea >> ContextArea # XXX PTaskEnv >> ContextEnv if not isinstance(spec, PTaskSpec): spec = PTaskSpec.get(spec, relative_to=relative_to) return super(Product, cls).get(spec)
def get(cls, spec, relative_to=None): # convenience that allows calling code to not have to type check # input that allows either spec or ptask if isinstance(spec, PTask): return spec if not isinstance(spec, PTaskSpec): spec = PTaskSpec.get(spec, relative_to=relative_to) # empty spec if not spec: raise PTaskError("Invalid empty spec supplied for ptask.") return super(PTask, cls).get(spec)
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): 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): 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): 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
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
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
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
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
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
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
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
def spec(self): """:returns: PTaskSpec object representing this ptask's spec.""" return PTaskSpec.get(self._data.get('spec'))
def validate(self): # need to identify the product version being subscribed to and the # ptask version subscribing to it. # get the product if not isinstance(self._product, Product): try: self._product = Product.get(self._product) except ProductError: raise ActionError("Unable to find product: " + str(self._product)) # get 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)) # find the version to subscribe to if isinstance(self._product_version, ProductVersion): pass elif self._product_version: matches = ProductVersion.list(product=self.product.spec, number=int(self._product_version)) if len(matches) != 1: raise ActionError( "Unable to find product '{p}' at version '{v}'".format( p=self.product.spec, v=self._product_version)) else: self._product_version = matches[0] else: # get the official version official_version = self._product.official_version if official_version: self._product_version = official_version else: # get the latest, non-deprecated version latest_published = self._product.latest_published() if latest_published: self._product_version = latest_published else: raise ActionError( "No available versions of product '{p}'".format( p=self._product.spec)) # find the version of the ptask doing the subscribing if isinstance(self._ptask_version, PTaskVersion): pass 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 the rules below need to be exposed outside of just the create # code. UIs, for example, should be able to check these cases before # allowing the user to perform actions... # if this ptask has any existing published versions, error out published = ProductVersion.list(ptask_version=self._ptask_version, published=True) if len(published) > 0: raise ActionError( "Unable to create new subscription. This ptask version " + \ "already has published product versions.\n" + \ "You need to version up to modify subscriptions." ) # see if there is an existing subscription: self._existing_sub = self._ptask_version.is_subscribed(self._product) if self._existing_sub: if (self._existing_sub.product_version_spec == \ self._product_version.spec): raise ActionError("Subscription already exists!") if self._product_version.deprecated: raise ActionError( "Product version is deprecated. Specify an alternate version.") # make sure product is published or from same ptask if (not self._product_version.published and not self._product.ptask_spec == self._ptask.spec): raise ActionError( "Product version is not published. Specify a published version." )
def prompt(self): parent_spec = PTaskSpec.parent(self.spec) template_options = [] if parent_spec: par_ptask = PTask.get(parent_spec) par_ptask_type = par_ptask.ptask_type else: par_ptask_type = 'none' ptask_area = PTaskArea(parent_spec, validate=False) master_config = ptask_area.config( PROJECT_MASTER_CONFIG_PATH, composite_ancestors=True, ) if not master_config or not hasattr(master_config, 'hierarchy'): raise ActionError("Unable to find project master config.") if not self.ptask_type in master_config.hierarchy[par_ptask_type]: raise ActionError( "Cannot create '{t}' ptask inside '{p}' ptask".format( t=self.ptask_type, p=par_ptask_type, )) # ---- prompt for missing fields if not self.source and self.ptask_type in master_config.templates: for template_spec in master_config.templates[self.ptask_type]: trimmed_spec = re.sub("^templates?=", "", template_spec, flags=re.IGNORECASE) template_options.append( (re.sub("[=_-]+", " ", trimmed_spec).title(), template_spec)) self._source = Output.prompt_menu( "Select a template to source", prompt_str="Selection", options=template_options, help_str="Please choose from the templates listed.", none_option=True, custom_prompt="Custom Source", custom_blank=False) # see if the ptask already exists if not self.ptask: try: self._ptask = PTask.get(self.spec) except PTaskError: pass else: if not self.force: raise ActionAborted("PTask already exists.") else: if not self._description: self._description = self.ptask.description if not self._start_date: self._start_date = self.ptask.start_date if not self._due_date: self._due_date = self.ptask.due_date if (not self.description or not self.start_date or not self.due_date): if self.force: raise ActionError( "Cannot force creation without required fields.") else: print "\nPlease enter information about this new {b}{t}{r}:".\ format( b=Style.bright, t=self.ptask_type, r=Style.reset, ) ptask_display = " [{pt}] {b}{s}{r}".format( pt=self.ptask_type, b=Style.bright, s=self.spec, r=Style.reset, ) if not self.description: self._description = Output.prompt( '{pd} description'.format(pd=ptask_display), blank=False, ) if not self.start_date: self._start_date = Output.prompt_date( '{pd} start date'.format(pd=ptask_display), blank=False, ) if not self.due_date: self._due_date = Output.prompt_date( '{pd} due date'.format(pd=ptask_display), blank=False, )
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.")
def prompt(self): parent_spec = PTaskSpec.parent(self.spec) template_options = [] if parent_spec: par_ptask = PTask.get(parent_spec) par_ptask_type = par_ptask.ptask_type else: par_ptask_type = 'none' ptask_area = PTaskArea(parent_spec, validate=False) master_config = ptask_area.config( PROJECT_MASTER_CONFIG_PATH, composite_ancestors=True, ) if not master_config or not hasattr(master_config, 'hierarchy'): raise ActionError("Unable to find project master config.") if not self.ptask_type in master_config.hierarchy[par_ptask_type]: raise ActionError( "Cannot create '{t}' ptask inside '{p}' ptask".format( t=self.ptask_type, p=par_ptask_type, ) ) # ---- prompt for missing fields if not self.source and self.ptask_type in master_config.templates: for template_spec in master_config.templates[self.ptask_type]: trimmed_spec = re.sub( "^templates?=", "", template_spec, flags=re.IGNORECASE ) template_options.append( ( re.sub("[=_-]+", " ", trimmed_spec).title(), template_spec ) ) self._source = Output.prompt_menu( "Select a template to source", prompt_str="Selection", options=template_options, help_str="Please choose from the templates listed.", none_option=True, custom_prompt="Custom Source", custom_blank=False ) # see if the ptask already exists if not self.ptask: try: self._ptask = PTask.get(self.spec) except PTaskError: pass else: if not self.force: raise ActionAborted("PTask already exists.") else: if not self._description: self._description = self.ptask.description if not self._start_date: self._start_date = self.ptask.start_date if not self._due_date: self._due_date = self.ptask.due_date if (not self.description or not self.start_date or not self.due_date): if self.force: raise ActionError( "Cannot force creation without required fields." ) else: print "\nPlease enter information about this new {b}{t}{r}:".\ format( b=Style.bright, t=self.ptask_type, r=Style.reset, ) ptask_display = " [{pt}] {b}{s}{r}".format( pt=self.ptask_type, b=Style.bright, s=self.spec, r=Style.reset, ) if not self.description: self._description = Output.prompt( '{pd} description'.format(pd=ptask_display), blank=False, ) if not self.start_date: self._start_date = Output.prompt_date( '{pd} start date'.format(pd=ptask_display), blank=False, ) if not self.due_date: self._due_date = Output.prompt_date( '{pd} due date'.format(pd=ptask_display), blank=False, )
def validate(self): # need to identify the product version being subscribed to and the # ptask version subscribing to it. # get the product if not isinstance(self._product, Product): try: self._product = Product.get(self._product) except ProductError: raise ActionError("Unable to find product: " + str(self._product)) # get 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)) # find the version to subscribe to if isinstance(self._product_version, ProductVersion): pass elif self._product_version: matches = ProductVersion.list(product=self.product.spec, number=int(self._product_version)) if len(matches) != 1: raise ActionError( "Unable to find product '{p}' at version '{v}'".format(p=self.product.spec, v=self._product_version) ) else: self._product_version = matches[0] else: # get the official version official_version = self._product.official_version if official_version: self._product_version = official_version else: # get the latest, non-deprecated version latest_published = self._product.latest_published() if latest_published: self._product_version = latest_published else: raise ActionError("No available versions of product '{p}'".format(p=self._product.spec)) # find the version of the ptask doing the subscribing if isinstance(self._ptask_version, PTaskVersion): pass 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 the rules below need to be exposed outside of just the create # code. UIs, for example, should be able to check these cases before # allowing the user to perform actions... # if this ptask has any existing published versions, error out published = ProductVersion.list(ptask_version=self._ptask_version, published=True) if len(published) > 0: raise ActionError( "Unable to create new subscription. This ptask version " + "already has published product versions.\n" + "You need to version up to modify subscriptions." ) # see if there is an existing subscription: self._existing_sub = self._ptask_version.is_subscribed(self._product) if self._existing_sub: if self._existing_sub.product_version_spec == self._product_version.spec: raise ActionError("Subscription already exists!") if self._product_version.deprecated: raise ActionError("Product version is deprecated. Specify an alternate version.") # make sure product is published or from same ptask if not self._product_version.published and not self._product.ptask_spec == self._ptask.spec: raise ActionError("Product version is not published. Specify a published version.")
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
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)
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)