@@ -450,7 +450,7 @@ class LocalDeployType:
450450 """LocalDeployType deals with local only deployments.
451451 """
452452
453- async def resolve (self , url , architecture ,
453+ async def resolve (self , charm_path , architecture ,
454454 app_name = None , channel = None , series = None ,
455455 revision = None , entity_url = None , force = False ,
456456 model_conf = None ):
@@ -461,36 +461,27 @@ async def resolve(self, url, architecture,
461461 -- revision flag is ignored for local charms
462462 """
463463
464- entity_url = url .path ()
465- entity_path = Path (entity_url )
466- bundle_path = entity_path / 'bundle.yaml'
464+ entity_path = Path (charm_path )
465+ if entity_path .suffix == '.yaml' :
466+ bundle_path = entity_path
467+ else :
468+ bundle_path = entity_path / 'bundle.yaml'
467469
468- identifier = entity_url
469470 origin = client .CharmOrigin (source = "local" , architecture = architecture )
470471 if not (entity_path .is_dir () or entity_path .is_file ()):
471472 raise JujuError ('{} path not found' .format (entity_url ))
472473
473- is_bundle = (
474- (entity_path .suffix == ".yaml" and entity_path .exists ()) or
475- bundle_path .exists ()
476- )
474+ is_bundle = bundle_path .exists ()
477475
478476 if app_name is None :
479- app_name = url .name
480-
481- if not is_bundle :
482- entity_url = url .path ()
483- entity_path = Path (entity_url )
484- if entity_path .suffix == '.charm' :
485- with zipfile .ZipFile (str (entity_path ), 'r' ) as charm_file :
486- metadata = yaml .load (charm_file .read ('metadata.yaml' ), Loader = yaml .FullLoader )
487- else :
488- metadata_path = entity_path / 'metadata.yaml'
489- metadata = yaml .load (metadata_path .read_text (), Loader = yaml .FullLoader )
490- app_name = metadata ['name' ]
477+ if is_bundle :
478+ bundle_with_overlays = [b for b in yaml .safe_load_all (bundle_path .read_text ())]
479+ app_name = bundle_with_overlays [0 ].get ('name' , '' )
480+ else :
481+ app_name = utils .get_local_charm_metadata (entity_path )["name" ]
491482
492483 return DeployTypeResult (
493- identifier = identifier ,
484+ identifier = charm_path ,
494485 origin = origin ,
495486 app_name = app_name ,
496487 is_local = True ,
@@ -541,7 +532,7 @@ async def resolve(self, url, architecture,
541532 raise JujuError ('revision and channel are mutually exclusive when deploying a bundle. Please choose one.' )
542533
543534 if app_name is None :
544- app_name = url .name
535+ app_name = charm_url .name
545536
546537 return DeployTypeResult (
547538 identifier = str (charm_url ),
@@ -591,8 +582,8 @@ def __init__(
591582 self ._charmhub = CharmHub (self )
592583
593584 self .deploy_types = {
594- "local" : LocalDeployType (),
595- "ch" : CharmhubDeployType (self ._resolve_charm ),
585+ Schema . LOCAL : LocalDeployType (),
586+ Schema . CHARM_HUB : CharmhubDeployType (self ._resolve_charm ),
596587 }
597588
598589 def is_connected (self ):
@@ -1670,7 +1661,7 @@ async def deploy(
16701661 storage = None , to = None , devices = None , trust = False , attach_storage = []):
16711662 """Deploy a new service or bundle.
16721663
1673- :param str entity_url: Charm or bundle url
1664+ :param str entity_url: Charm or bundle to deploy. Charm url or file path
16741665 :param str application_name: Name to give the service
16751666 :param dict bind: <charm endpoint>:<network space> pairs
16761667 :param str channel: Charm store channel from which to retrieve
@@ -1716,26 +1707,33 @@ async def deploy(
17161707 raise JujuError ("Expected attach_storage to be a list of strings, given {}" .format (attach_storage ))
17171708
17181709 # Ensure what we pass in, is a string.
1719- entity_url = str (entity_url )
1720- if is_local_charm (entity_url ) and not entity_url .startswith ("local:" ):
1721- entity_url = "local:{}" .format (entity_url )
1710+ entity = str (entity_url )
1711+ if is_local_charm (entity ):
1712+ if entity .startswith ("local:" ):
1713+ entity = entity [6 :]
1714+ architecture = await self ._resolve_architecture ()
1715+ schema = Schema .LOCAL
17221716
1723- if client .CharmsFacade .best_facade_version (self .connection ()) < 3 :
1724- url = URL .parse (str (entity_url ), default_store = Schema .CHARM_STORE )
17251717 else :
1726- url = URL .parse (str (entity_url ))
1718+ if client .CharmsFacade .best_facade_version (self .connection ()) < 3 :
1719+ url = URL .parse (entity , default_store = Schema .CHARM_STORE )
1720+ else :
1721+ url = URL .parse (entity )
1722+ entity = str (url )
17271723
1728- architecture = await self ._resolve_architecture (url )
1724+ architecture = await self ._resolve_architecture (url )
1725+ schema = url .schema
1726+ name = url .name
17291727
1730- if str ( url . schema ) not in self .deploy_types :
1731- raise JujuError ("unknown deploy type {}, expected charmhub or local" .format (url . schema ))
1728+ if schema not in self .deploy_types :
1729+ raise JujuError ("unknown deploy type {}, expected charmhub or local" .format (schema ))
17321730
17331731 model_conf = await self .get_config ()
1734- res = await self .deploy_types [str ( url . schema ) ].resolve (url , architecture ,
1735- application_name , channel ,
1736- series , revision ,
1737- entity_url , force ,
1738- model_conf )
1732+ res = await self .deploy_types [schema ].resolve (entity , architecture ,
1733+ application_name , channel ,
1734+ series , revision ,
1735+ entity_url , force ,
1736+ model_conf )
17391737
17401738 if res .identifier is None :
17411739 raise JujuError ('unknown charm or bundle {}' .format (entity_url ))
@@ -1750,7 +1748,7 @@ async def deploy(
17501748
17511749 if res .is_bundle :
17521750 handler = BundleHandler (self , trusted = trust , forced = force )
1753- await handler .fetch_plan (url , charm_origin , overlays = overlays )
1751+ await handler .fetch_plan (entity , charm_origin , overlays = overlays )
17541752 await handler .execute_plan ()
17551753 extant_apps = {app for app in self .applications }
17561754 pending_apps = handler .applications - extant_apps
@@ -1778,8 +1776,7 @@ async def deploy(
17781776 charm_origin )
17791777 else :
17801778 charm_origin = add_charm_res .charm_origin
1781- if Schema .CHARM_HUB .matches (url .schema ):
1782-
1779+ if Schema .CHARM_HUB .matches (schema ):
17831780 if client .ApplicationFacade .best_facade_version (self .connection ()) >= 19 :
17841781 server_side_deploy = True
17851782 else :
@@ -1793,7 +1790,7 @@ async def deploy(
17931790 identifier ,
17941791 add_charm_res .charm_origin )
17951792
1796- is_sub = await self .charmhub .is_subordinate (url . name )
1793+ is_sub = await self .charmhub .is_subordinate (name )
17971794 if is_sub :
17981795 if num_units > 1 :
17991796 raise JujuError ("cannot use num_units with subordinate application" )
@@ -1879,7 +1876,7 @@ async def _resolve_charm(self, url, origin, force=False, series=None, model_conf
18791876 Returns the confirmed origin returned by the Juju API to be used in
18801877 calls like ApplicationFacade.Deploy
18811878
1882- :returns str , client.CharmOrigin, [str]
1879+ :returns url.URL , client.CharmOrigin, [str]
18831880 """
18841881 charms_cls = client .CharmsFacade
18851882 if charms_cls .best_facade_version (self .connection ()) < 3 :
@@ -1919,16 +1916,18 @@ async def _resolve_charm(self, url, origin, force=False, series=None, model_conf
19191916 result .charm_origin .base = utils .get_base_from_origin_or_channel (resolved_origin , selected_series )
19201917 charm_url .series = selected_series
19211918
1922- return str ( charm_url ) , resolved_origin
1919+ return charm_url , resolved_origin
19231920
1924- async def _resolve_architecture (self , url ):
1921+ async def _resolve_architecture (self , url = None ):
19251922 """_resolve_architecture returns the architecture for a given charm url.
1923+ If the charm url is absent, or doesn't specific an arch, we return the
1924+ default architecture from the model.
1925+
19261926 :param str url: the client.URL to determine the arch for
19271927
19281928 :returns str architecture for the given url
19291929 """
1930-
1931- if url .architecture :
1930+ if url is not None and url .architecture :
19321931 return url .architecture
19331932
19341933 constraints = await self .get_constraints ()
0 commit comments