def plan_layers(self, layers, output_files): next_config = BuildConfig() next_config.add_config(layers["layers"][0].config) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info("Processing layer: %s%s", layer.url, "" if 'deps' in layer.directory.splitall() else " (from %s)" % layer.directory.relpath()) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] next_config = next_config.add_config(next_layer.config) else: # Add an empty level to the configs to represent that there # is no layer after the current one. This is important for # the IgnoreTactic, which needs to look ahead so that it can # handle ignoring entire directories. next_config = next_config.add_config({}) list(e for e in utils.walk(layer.directory, self.build_tactics, layer=layer, next_config=next_config, output_files=output_files)) plan = [t for t in output_files.values() if t] return plan
def plan_layers(self, layers, output_files): next_config = BuildConfig() next_config.add_config(layers["layers"][0].config) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info( "Processing layer: %s%s", layer.url, "" if 'deps' in layer.directory.splitall() else " (from %s)" % layer.directory.relpath()) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] next_config = next_config.add_config(next_layer.config) else: # Add an empty level to the configs to represent that there # is no layer after the current one. This is important for # the IgnoreTactic, which needs to look ahead so that it can # handle ignoring entire directories. next_config = next_config.add_config({}) list(e for e in utils.walk(layer.directory, self.build_tactics, layer=layer, next_config=next_config, output_files=output_files)) plan = [t for t in output_files.values() if t] return plan
def plan_layers(self, layers, output_files): config = BuildConfig() cfgfn = layers["layers"][0] / BuildConfig.DEFAULT_FILE if cfgfn.exists(): config = config.add_config( cfgfn, True) else: cfgfn = layers["layers"][0] / BuildConfig.OLD_CONFIG config = config.add_config( cfgfn, True) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info("Processing layer: %s", layer.url) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] config = config.add_config( next_layer / BuildConfig.DEFAULT_FILE, True) list(e for e in utils.walk(layer.directory, self.build_tactics, current=layer, config=config, output_files=output_files)) plan = [t for t in output_files.values() if t] return plan
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 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 sign(self): """return sign in the form {relpath: (origin layer, SHA256)} """ sigs = {} for entry, sig in utils.walk(self.target, utils.sign, kind="files"): relpath = entry.relpath(self._target.directory) sigs[relpath] = (self.interface.url, "static", sig) return sigs
def sign(self): "" # suppress inherited doc # Sign all of the files that were put into place. sigs = {} for entry, sig in utils.walk(self.target, utils.sign, kind="files"): relpath = entry.relpath(self._target.directory) sigs[relpath] = (self.interface.url, "static", sig) return sigs
def sign(self): "" # suppress inherited doc sigs = {} for d in self._tracked: if d.isdir(): for entry, sig in utils.walk(d, utils.sign, kind="files"): relpath = entry.relpath(self.target.directory) sigs[relpath] = (self.layer.url, "dynamic", sig) elif d.isfile(): relpath = d.relpath(self.target.directory) sigs[relpath] = (self.layer.url, "dynamic", utils.sign(d)) return sigs
def sign(self): """return sign in the form {relpath: (origin layer, SHA256)} """ sigs = {} for d in self._tracked: if d.isdir(): for entry, sig in utils.walk(d, utils.sign, kind="files"): relpath = entry.relpath(self.target.directory) sigs[relpath] = (self.current.url, "dynamic", sig) elif d.isfile(): relpath = d.relpath(self.target.directory) sigs[relpath] = (self.current.url, "dynamic", utils.sign(d)) return sigs
def sign(self): "" # suppress inherited doc sigs = {} for d in self._tracked: if d.isdir(): for entry, sig in utils.walk(d, utils.sign, kind="files"): relpath = entry.relpath(self.target.directory) sigs[relpath] = (self.layer.url, "dynamic", sig) elif d.isfile(): relpath = d.relpath(self.target.directory) sigs[relpath] = ( self.layer.url, "dynamic", utils.sign(d)) return sigs
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 plan_layers(self, layers, output_files): current_config = BuildConfig() next_config = current_config.add_config(layers["layers"][0].config) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info( "Processing layer: %s%s", layer.url, "" if layer.directory.startswith(self.cache_dir) else " (from %s)" % layer.directory.relpath()) current_config = current_config.add_config(layer.config) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] next_config = next_config.add_config(next_layer.config) else: # Add an empty level to the configs to represent that there # is no layer after the current one. This is important for # the IgnoreTactic, which needs to look ahead so that it can # handle ignoring entire directories. next_config = next_config.add_config({}) list(e for e in utils.walk(layer.directory, self.build_tactics, layer=layer, next_config=next_config, current_config=current_config, output_files=output_files)) if self.wheelhouse_overrides: existing_tactic = output_files.get('wheelhouse.txt') wh_over_layer = Layer('--wheelhouse-overrides', layers["layers"][-1].target_repo.dirname()) wh_over_layer.directory = layers["layers"][-1].directory output_files['wheelhouse.txt'] = WheelhouseTactic( self.wheelhouse_overrides, self.target, wh_over_layer, next_config, ) output_files['wheelhouse.txt'].purge_wheels = True if existing_tactic is not None: output_files['wheelhouse.txt'].combine(existing_tactic) plan = [t for t in output_files.values() if t] return plan
def plan_layers(self, layers, output_files): config = ComposerConfig() config = config.add_config( layers["layers"][0] / ComposerConfig.DEFAULT_FILE, True) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info("Processing layer: %s", layer.url) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] config = config.add_config( next_layer / ComposerConfig.DEFAULT_FILE, True) list(e for e in utils.walk(layer.directory, self.build_tactics, current=layer, config=config, output_files=output_files)) plan = [t for t in output_files.values() if t] return plan
def plan_layers(self, layers, output_files): current_config = BuildConfig() next_config = current_config.add_config(layers["layers"][0].config) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info("Processing layer: %s%s", layer.url, "" if layer.directory.startswith(self.cache_dir) else " (from %s)" % layer.directory.relpath()) current_config = current_config.add_config(layer.config) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] next_config = next_config.add_config(next_layer.config) else: # Add an empty level to the configs to represent that there # is no layer after the current one. This is important for # the IgnoreTactic, which needs to look ahead so that it can # handle ignoring entire directories. next_config = next_config.add_config({}) list(e for e in utils.walk(layer.directory, self.build_tactics, layer=layer, next_config=next_config, current_config=current_config, output_files=output_files)) if self.wheelhouse_overrides: existing_tactic = output_files.get('wheelhouse.txt') output_files['wheelhouse.txt'] = WheelhouseTactic( str(self.wheelhouse_overrides), self.target, layers["layers"][-1], next_config, ) output_files['wheelhouse.txt'].purge_wheels = True if existing_tactic is not None: output_files['wheelhouse.txt'].combine(existing_tactic) plan = [t for t in output_files.values() if t] return plan
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 plan_layers(self, layers, output_files): current_config = BuildConfig() next_config = current_config.add_config(layers["layers"][0].config) layers["layers"][-1].url = self.name for i, layer in enumerate(layers["layers"]): log.info( "Processing layer: %s%s", layer.url, "" if layer.directory.startswith(self.cache_dir) else " (from %s)" % layer.directory.relpath()) current_config = current_config.add_config(layer.config) if i + 1 < len(layers["layers"]): next_layer = layers["layers"][i + 1] next_config = next_config.add_config(next_layer.config) else: # Add an empty level to the configs to represent that there # is no layer after the current one. This is important for # the IgnoreTactic, which needs to look ahead so that it can # handle ignoring entire directories. next_config = next_config.add_config({}) list(e for e in utils.walk(layer.directory, self.build_tactics, layer=layer, next_config=next_config, current_config=current_config, output_files=output_files)) # now we do update the wheelhouse.txt output file with the lock file if # necessary. if not getattr(self, 'ignore_lock_file', False): lines = self.generate_python_modules_from_lock_file() # override any existing lines with the python modules from the lock # file. existing_tactic = output_files.get('wheelhouse.txt') lock_layer = Layer('lockfile-wheelhouse', layers["layers"][-1].target_repo.dirname()) lock_layer.directory = layers["layers"][-1].directory wh_tactic = WheelhouseTactic( "", self.target, lock_layer, next_config, ) wh_tactic.lines = lines wh_tactic.purge_wheels = True if existing_tactic is not None: wh_tactic.combine(existing_tactic) output_files["wheelhouse.txt"] = wh_tactic if self.wheelhouse_overrides: existing_tactic = output_files.get('wheelhouse.txt') wh_over_layer = Layer('--wheelhouse-overrides', layers["layers"][-1].target_repo.dirname()) wh_over_layer.directory = layers["layers"][-1].directory output_files['wheelhouse.txt'] = WheelhouseTactic( self.wheelhouse_overrides, self.target, wh_over_layer, next_config, ) output_files['wheelhouse.txt'].purge_wheels = True if existing_tactic is not None: output_files['wheelhouse.txt'].combine(existing_tactic) plan = [t for t in output_files.values() if t] return plan
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)