def push(self): """Pushes a built charm to Charmstore""" if "override-push" in self.opts: self.echo("Override push found, running in place of charm push.") script( self.opts["override-push"], cwd=self.src_path, charm=self.name, namespace=self.namespace, echo=self.echo, ) return self.echo(f"Pushing built {self.dst_path} to {self.entity}") out = retry_call( capture, fargs=[["charm", "push", self.dst_path, self.entity]], fkwargs={"check": True}, delay=2, backoff=2, exceptions=CalledProcessError, ) self.echo(f"Charm push returned: {out}") # Output includes lots of ansi escape sequences from the docker push, # and we only care about the first line, which contains the url as yaml. out = yaml.safe_load(out.stdout.decode().strip().splitlines()[0]) self.new_entity = out["url"] self.echo(f"Setting {self.new_entity} metadata: {self.commit}") cmd_ok(["charm", "set", self.new_entity, f"commit={self.commit}"], echo=self.echo)
def charm_build(self): """Perform a build against charm/bundle.""" lxc = os.environ.get("charmcraft_lxc") ret = SimpleNamespace(ok=False) if "override-build" in self.opts: self.echo("Override build found, running in place of charm build.") ret = script( self.opts["override-build"], cwd=self.src_path, charm=self.name, echo=self.echo, ) elif self.reactive: args = "-r --force -i https://localhost" if self.store == "ch": args += " --charm-file" else: self.dst_path = str(self.build.build_dir / self.name) self.echo(f"Building with: charm build {args}") ret = CharmCmd(self).build(*args.split(), _cwd=self.src_path) elif lxc: self.echo(f"Building in container {lxc}") repository = f"https://github.com/{self.downstream}" charmcraft_script = ( "#!/bin/bash -eux\n" f"source {Path(__file__).parent / 'charmcraft-lib.sh'}\n" f"ci_charmcraft_pack {lxc} {repository} {self.branch} {self.opts.get('subdir', '')}\n" f"ci_charmcraft_copy {lxc} {self.dst_path}\n") ret = script(charmcraft_script, echo=self.echo) else: self.echo("No 'charmcraft_lxc' container available") if not ret.ok: self.echo("Failed to build, aborting") raise BuildException(f"Failed to build {self.name}")
def charm_build(self): """Perform charm build against charm/bundle""" if "override-build" in self.opts: self.echo("Override build found, running in place of charm build.") ret = script( self.opts["override-build"], cwd=self.src_path, charm=self.name, echo=self.echo, ) elif self.legacy_charm: cmd = "charm build -r --force -i https://localhost" self.echo(f"Building with: {cmd}") ret = cmd_ok( cmd, cwd=self.src_path, echo=self.echo, ) else: cmd = f"charmcraft build -f {self.src_path}" self.echo(f"Building with: {cmd}") ret = cmd_ok( cmd, cwd=self.build.build_dir, echo=self.echo, ) if not ret.ok: self.echo("Failed to build, aborting") raise SystemExit(f"Failed to build {self.name}")
def attach_resources(self): out_path = Path(self.src_path) / "tmp" os.makedirs(str(out_path), exist_ok=True) resource_spec = yaml.safe_load( Path(self.build.resource_spec).read_text()) resources = resource_spec.get(self.entity, {}) # Build any custom resources. resource_builder = self.opts.get("build-resources", None) if resource_builder and not resources: raise SystemExit( "Custom build-resources specified for {self.entity} but no spec found" ) if resource_builder: resource_builder = resource_builder.format( out_path=out_path, src_path=self.src_path, ) self.echo("Running custom build-resources") ret = script(resource_builder, echo=self.echo) if not ret.ok: raise SystemExit("Failed to build custom resources") # Pull any `upstream-image` annotated resources. for name, details in self._read_metadata_resources().items(): upstream_image = details.get("upstream-source") if details["type"] == "oci-image" and upstream_image: self.echo(f"Pulling {upstream_image}...") sh.docker.pull(upstream_image) resources[name] = upstream_image self.echo(f"Attaching resources:\n{pformat(resources)}") # Attach all resources. for name, resource in resources.items(): # If the resource is a file, populate the path where it was built. # If it's a custom image, it will be in Docker and this will be a no-op. resource = resource.format(out_path=out_path) retry_call( cmd_ok, fargs=[[ "charm", "attach", self.new_entity, f"{name}={resource}", ]], fkwargs={ "check": True, "echo": self.echo }, delay=2, backoff=2, tries=15, exceptions=CalledProcessError, )
def attach_resources(self): """Assemble charm's resources and associate in the store.""" out_path = Path(self.src_path) / "tmp" os.makedirs(str(out_path), exist_ok=True) resource_spec = yaml.safe_load( Path(self.build.resource_spec).read_text()) resource_spec = resource_spec.get(self.name, {}) # Build any custom resources. resource_builder = self.opts.get("build-resources", None) if resource_builder and not resource_spec: raise BuildException( f"Custom build-resources specified for {self.name} but no spec found" ) if resource_builder: resource_builder = resource_builder.format( out_path=out_path, src_path=self.src_path, ) self.echo("Running custom build-resources") ret = script(resource_builder, echo=self.echo) if not ret.ok: raise BuildException("Failed to build custom resources") for name, details in self._read_metadata_resources().items(): resource_fmt = resource_spec.get(name) if not resource_fmt: # ignore pushing a resource not defined in `resource_spec` continue if details["type"] == "oci-image": upstream_source = details.get("upstream-source") if upstream_source: # Pull any `upstream-image` annotated resources. self.echo(f"Pulling {upstream_source}...") sh.docker.pull(upstream_source) resource_fmt = upstream_source resource_spec[name] = ("image", resource_fmt) elif details["type"] == "file": resource_spec[name] = ( "filepath", resource_fmt.format(out_path=out_path), ) self.echo(f"Attaching resources:\n{pformat(resource_spec)}") # Attach all resources. for resource_name, resource in resource_spec.items(): if self.store == "cs": _CharmStore(self).upload_resource(self.new_entity, resource_name, resource[1]) elif self.store == "ch": _CharmHub(self).upload_resource(self.entity, resource_name, resource)
def push(self): """Pushes a built charm to Charm store/hub.""" if "override-push" in self.opts: self.echo("Override push found, running in place of charm push.") script( self.opts["override-push"], cwd=self.src_path, charm=self.name, namespace=self.namespace, echo=self.echo, ) return self.echo( f"Pushing {self.type}({self.name}) from {self.dst_path} to {self.entity}" ) if self.store == "cs": cs = _CharmStore(self) self.new_entity = cs.upload(self.dst_path, self.entity) cs.set(self.new_entity, self.commit) elif self.store == "ch": self.new_entity = _CharmHub(self).upload(self.dst_path)