def exec_plan(self, plan=None, layers=None): signatures = {} cont = True for phase in self.PHASES: for tactic in plan: if phase == "lint": cont &= tactic.lint() if cont is False and self.force is not True: return elif phase == "read": # We use a read (into memory phase to make layer comps # simpler) tactic.read() elif phase == "call": tactic() elif phase == "sign": sig = tactic.sign() if sig: signatures.update(sig) new_repo = not self.manifest.exists() if new_repo: added, changed, removed = set(), set(), set() else: ignores = utils.ignore_matcher(DEFAULT_IGNORES) added, changed, _ = utils.delta_signatures(self.manifest, ignores) removed = self.clean_removed(signatures) # write out the sigs if "sign" in self.PHASES: self.write_signatures(signatures, layers) if self.report: self.write_report(new_repo, added, changed, removed)
def lint(self): "" # suppress inherited doc # Ensure that the interface layer used is valid. impl = self.interface.directory / self.role + '.py' if not impl.exists(): log.error('Missing implementation for interface role: %s.py', self.role) return False valid = True ignorer = utils.ignore_matcher(self.config.ignores + self.interface.config.ignores + self.config.excludes + self.interface.config.excludes) for entry, _ in utils.walk(self.interface.directory, lambda x: True, matcher=ignorer, kind="files"): if entry.splitext()[1] != ".py": continue relpath = entry.relpath(self._target.directory) target = self._target.directory / relpath if not target.exists(): continue unchanged = utils.delta_python_dump(entry, target, from_name=relpath) if not unchanged: valid = False return valid
def lint(self): "" # suppress inherited doc # Ensure that the interface layer used is valid. impl = self.interface.directory / self.role + '.py' if not impl.exists(): log.error('Missing implementation for interface role: %s.py', self.role) return False valid = True ignorer = utils.ignore_matcher(self.config.ignores + self.interface.config.ignores) for entry, _ in utils.walk(self.interface.directory, lambda x: True, matcher=ignorer, kind="files"): if entry.splitext()[1] != ".py": continue relpath = entry.relpath(self._target.directory) target = self._target.directory / relpath if not target.exists(): continue unchanged = utils.delta_python_dump(entry, target, from_name=relpath) if not unchanged: valid = False return valid
def inspect(charm, force_styling=False): tw = utils.TermWriter(force_styling=force_styling) manp = charm / ".composer.manifest" comp = charm / "composer.yaml" if not manp.exists() or not comp.exists(): return manifest = json.loads(manp.text()) composer = yaml.load(comp.open()) a, c, d = utils.delta_signatures(manp) # ordered list of layers used for legend layers = list(manifest['layers']) def get_depth(e): rel = e.relpath(charm) depth = len(rel.splitall()) - 2 return rel, depth def get_suffix(rel): suffix = "" if rel in a: suffix = "+" elif rel in c: suffix = "*" return suffix def get_color(rel): # name of layer this belongs to color = tw.term.normal if rel in manifest['signatures']: layer = manifest['signatures'][rel][0] layer_key = layers.index(layer) color = getattr(tw, theme.get(layer_key, "normal")) else: if entry.isdir(): color = tw.blue return color tw.write("Inspect %s\n" % composer["is"]) for layer in layers: tw.write("# {color}{layer}{t.normal}\n", color=getattr(tw, theme.get(layers.index(layer), "normal")), layer=layer) tw.write("\n") tw.write("{t.blue}{target}{t.normal}\n", target=charm) ignorer = utils.ignore_matcher(config.DEFAULT_IGNORES) walk = sorted(utils.walk(charm, get_depth), key=lambda x: x[1][0]) for i in range(len(walk) - 1): entry, (rel, depth) = walk[i] nEnt, (nrel, ndepth) = walk[i + 1] if not ignorer(rel): continue tw.write("{prefix}{layerColor}{entry} " "{t.bold}{suffix}{t.normal}\n", prefix=get_prefix(walk, i, depth, ndepth), layerColor=get_color(rel), suffix=get_suffix(rel), entry=rel.name)
def validate(self): p = self.target_dir / ".build.manifest" if not p.exists(): return [], [], [] ignorer = utils.ignore_matcher(DEFAULT_IGNORES) a, c, d = utils.delta_signatures(p, ignorer) for f in a: log.warn( "Added unexpected file, should be in a base layer: %s", f) for f in c: log.warn( "Changed file owned by another layer: %s", f) for f in d: log.warn( "Deleted a file owned by another layer: %s", f) if a or c or d: if self.force is True: log.info( "Continuing with known changes to target layer. " "Changes will be overwritten") else: raise ValueError( "Unable to continue due to unexpected modifications " "(try --force)") return a, c, d
def trigger(cls, entity, target, layer, next_config): """ Match if the given entity is excluded by the current layer. """ relpath = entity.relpath(layer.directory) excluded = utils.ignore_matcher(layer.config.excludes) return not excluded(relpath)
def validate(self): p = self.target_dir / ".composer.manifest" if not p.exists(): return [], [], [] ignorer = utils.ignore_matcher(DEFAULT_IGNORES) a, c, d = utils.delta_signatures(p, ignorer) for f in a: log.warn( "Added unexpected file, should be in a base layer: %s", f) for f in c: log.warn( "Changed file owned by another layer: %s", f) for f in d: log.warn( "Deleted a file owned by another layer: %s", f) if a or c or d: if self.force is True: log.info( "Continuing with known changes to target layer. " "Changes will be overwritten") else: raise ValueError( "Unable to continue due to unexpected modifications (try --force)") return a, c, d
def trigger(cls, entity, target, layer, next_config): """ Match if the given entity will be ignored by the next layer. """ relpath = entity.relpath(layer.directory) ignored = utils.ignore_matcher(next_config.ignores) return not ignored(relpath)
def __call__(self): if self.entity.isdir(): return should_ignore = utils.ignore_matcher(self.target.config.ignores) if not should_ignore(self.relpath): return target = self.target_file log.debug("Copying %s: %s", self.layer_name, target) # Ensure the path exists target.dirname().makedirs_p() if (self.entity != target) and not target.exists() or not self.entity.samefile(target): data = self.read() if data: target.write_bytes(data) self.entity.copymode(target) else: self.entity.copy2(target)
def __call__(self): if self.entity.isdir(): return should_ignore = utils.ignore_matcher(self.target.config.ignores) if not should_ignore(self.relpath): return target = self.target_file log.debug("Copying %s: %s", self.layer_name, target) # Ensure the path exists target.dirname().makedirs_p() if (self.entity != target) and not target.exists() \ or not self.entity.samefile(target): data = self.read() if data: target.write_bytes(data) self.entity.copymode(target) else: self.entity.copy2(target)
def __call__(self): # copy the entire tree into the # hooks/relations/<interface> # directory log.debug("Copying Interface %s: %s", self.interface.name, self.target) ignorer = utils.ignore_matcher(self.config.ignores) for entity, _ in utils.walk(self.interface.directory, lambda x: True, matcher=ignorer, kind="files"): target = entity.relpath(self.interface.directory) target = (self.target / target).normpath() target.parent.makedirs_p() entity.copy2(target) init = self.target / "__init__.py" if not init.exists(): # ensure we can import from here directly init.touch()
def __call__(self): # copy the entire tree into the # hooks/relations/<interface> # directory log.debug("Copying Interface %s: %s", self.interface.name, self.target) # Ensure the path exists if self.target.exists(): # XXX: fix this to do actual updates return ignorer = utils.ignore_matcher(self.config.ignores) for entity, _ in utils.walk(self.interface.directory, lambda x: True, matcher=ignorer, kind="files"): target = entity.relpath(self.interface.directory) target = (self.target / target).normpath() target.parent.makedirs_p() entity.copy2(target) init = self.target / "__init__.py" if not init.exists(): # ensure we can import from here directly init.touch()
def inspect(charm, force_styling=False, annotate=False): tw = utils.TermWriter(force_styling=force_styling) manp = charm / ".build.manifest" comp = charm / "layer.yaml" if not manp.exists() or not comp.exists(): return manifest = json.loads(manp.text()) composer = yaml.safe_load(comp.open()) a, c, d = utils.delta_signatures(manp) # ordered list of layers used for legend if isinstance(manifest['layers'][0], dict): layers = [layer['url'] for layer in manifest['layers']] else: layers = list(manifest['layers']) layers.reverse() while layers[0].startswith('interface:'): layers.append(layers.pop(0)) def get_depth(e): rel = e.relpath(charm) depth = len(rel.splitall()) - 2 return rel, depth def get_suffix(rel): suffix = "" if rel in a: suffix = "+" elif rel in c: suffix = "*" return suffix def get_color(rel): # name of layer this belongs to color = tw.term.normal if rel in manifest['signatures']: layer = manifest['signatures'][rel][0] if layer in layers: layer_key = layers.index(layer) else: # handle special build created artifacts, which have # a "layer name" of "build" (mostly the manifest itself) layer_key = -1 color = getattr(tw, theme.get(layer_key, "normal")) else: if entry.isdir(): color = tw.blue return color tw.write("Inspect %s\n" % composer["is"]) if tw.does_styling or force_styling: tw.write("\n") tw.write("Color key:\n") for i, layer in enumerate(layers): tw.write("# {color}{layer}{t.normal}\n", color=getattr(tw, theme.get(i, "normal")), layer=layer) else: # force annotations if we can't use color annotate = True tw.write("\n") tw.write("{t.blue}{target}{t.normal}\n", target=charm) ignorer = utils.ignore_matcher(config.DEFAULT_IGNORES) walk = sorted(utils.walk(charm, get_depth), key=lambda x: x[1][0]) for i in range(len(walk) - 1): entry, (rel, depth) = walk[i] nEnt, (nrel, ndepth) = walk[i + 1] if not ignorer(rel): continue if annotate and rel in manifest['signatures']: layer_name = manifest['signatures'][rel][0] if layer_name == 'build': # handle special build created artifacts, which have # a "layer name" of "build" (mostly the manifest itself) annotation = ' ({}build artifact{})'.format(tw.bright_black, tw.normal) else: annotation = ' (from {}{}{})'.format(get_color(rel), layer_name, tw.normal) else: annotation = '' tw.write("{prefix}{layerColor}{entry} " "{t.bold}{suffix}{t.normal}{annotation}\n", prefix=get_prefix(walk, i, depth, ndepth), layerColor=get_color(rel), suffix=get_suffix(rel), entry=rel.name, annotation=annotation)
def inspect(charm, force_styling=False): tw = utils.TermWriter(force_styling=force_styling) manp = charm / ".composer.manifest" comp = charm / "composer.yaml" if not manp.exists() or not comp.exists(): return manifest = json.loads(manp.text()) composer = yaml.load(comp.open()) a, c, d = utils.delta_signatures(manp) # ordered list of layers used for legend layers = list(manifest['layers']) def get_depth(e): rel = e.relpath(charm) depth = len(rel.splitall()) - 2 return rel, depth def get_suffix(rel): suffix = "" if rel in a: suffix = "+" elif rel in c: suffix = "*" return suffix def get_color(rel): # name of layer this belongs to color = tw.term.normal if rel in manifest['signatures']: layer = manifest['signatures'][rel][0] layer_key = layers.index(layer) color = getattr(tw, theme.get(layer_key, "normal")) else: if entry.isdir(): color = tw.blue return color tw.write("Inspect %s\n" % composer["is"]) for layer in layers: tw.write("# {color}{layer}{t.normal}\n", color=getattr(tw, theme.get( layers.index(layer), "normal")), layer=layer) tw.write("\n") tw.write("{t.blue}{target}{t.normal}\n", target=charm) ignorer = utils.ignore_matcher(config.DEFAULT_IGNORES) walk = sorted(utils.walk(charm, get_depth), key=lambda x: x[1][0]) for i in range(len(walk) - 1): entry, (rel, depth) = walk[i] nEnt, (nrel, ndepth) = walk[i + 1] if not ignorer(rel): continue tw.write("{prefix}{layerColor}{entry} " "{t.bold}{suffix}{t.normal}\n", prefix=get_prefix(walk, i, depth, ndepth), layerColor=get_color(rel), suffix=get_suffix(rel), entry=rel.name)
def inspect(charm, force_styling=False, annotate=False): tw = utils.TermWriter(force_styling=force_styling) manp = charm / ".build.manifest" comp = charm / "layer.yaml" if not manp.exists() or not comp.exists(): return manifest = json.loads(manp.text()) composer = yaml.safe_load(comp.open()) a, c, d = utils.delta_signatures(manp) # ordered list of layers used for legend if isinstance(manifest['layers'][0], dict): layers = [layer['url'] for layer in manifest['layers']] else: layers = list(manifest['layers']) layers.reverse() while layers[0].startswith('interface:'): layers.append(layers.pop(0)) def get_depth(e): rel = e.relpath(charm) depth = len(rel.splitall()) - 2 return rel, depth def get_suffix(rel): suffix = "" if rel in a: suffix = "+" elif rel in c: suffix = "*" return suffix def get_color(rel): # name of layer this belongs to color = tw.term.normal if rel in manifest['signatures']: layer = manifest['signatures'][rel][0] if layer in layers: layer_key = layers.index(layer) else: # handle special build created artifacts, which have # a "layer name" of "build" (mostly the manifest itself) layer_key = -1 color = getattr(tw, theme.get(layer_key, "normal")) else: if entry.isdir(): color = tw.blue return color tw.write("Inspect %s\n" % composer["is"]) if tw.does_styling or force_styling: tw.write("\n") tw.write("Color key:\n") for i, layer in enumerate(layers): tw.write("# {color}{layer}{t.normal}\n", color=getattr(tw, theme.get(i, "normal")), layer=layer) else: # force annotations if we can't use color annotate = True tw.write("\n") tw.write("{t.blue}{target}{t.normal}\n", target=charm) ignorer = utils.ignore_matcher(config.DEFAULT_IGNORES) walk = sorted(utils.walk(charm, get_depth), key=lambda x: x[1][0]) for i in range(len(walk) - 1): entry, (rel, depth) = walk[i] nEnt, (nrel, ndepth) = walk[i + 1] if not ignorer(rel): continue if annotate and rel in manifest['signatures']: layer_name = manifest['signatures'][rel][0] if layer_name == 'build': # handle special build created artifacts, which have # a "layer name" of "build" (mostly the manifest itself) annotation = ' ({}build artifact{})'.format( tw.bright_black, tw.normal) else: annotation = ' (from {}{}{})'.format(get_color(rel), layer_name, tw.normal) else: annotation = '' tw.write( "{prefix}{layerColor}{entry} " "{t.bold}{suffix}{t.normal}{annotation}\n", prefix=get_prefix(walk, i, depth, ndepth), layerColor=get_color(rel), suffix=get_suffix(rel), entry=rel.name, annotation=annotation)