@@ -934,35 +934,77 @@ def _check_requirements_has_idp_common_pkg(self, func_dir):
934934 def _extract_function_name (self , dir_name , template_path ):
935935 """Extract CloudFormation function name from template by matching CodeUri."""
936936 try :
937+ try :
938+ import yaml
939+ except ImportError :
940+ self .console .print ("[yellow]PyYAML not found, installing...[/yellow]" )
941+ subprocess .run (
942+ [sys .executable , "-m" , "pip" , "install" , "PyYAML" ], check = True
943+ )
944+ import yaml
945+
946+ # Create a custom loader that ignores CloudFormation intrinsic functions
947+ class CFLoader (yaml .SafeLoader ):
948+ pass
949+
950+ def construct_unknown (loader , node ):
951+ if isinstance (node , yaml .ScalarNode ):
952+ return loader .construct_scalar (node )
953+ elif isinstance (node , yaml .SequenceNode ):
954+ return loader .construct_sequence (node )
955+ elif isinstance (node , yaml .MappingNode ):
956+ return loader .construct_mapping (node )
957+ return None
958+
959+ # Add constructors for CloudFormation intrinsic functions
960+ cf_functions = [
961+ "!Ref" ,
962+ "!GetAtt" ,
963+ "!Join" ,
964+ "!Sub" ,
965+ "!Select" ,
966+ "!Split" ,
967+ "!Base64" ,
968+ "!GetAZs" ,
969+ "!ImportValue" ,
970+ "!FindInMap" ,
971+ "!Equals" ,
972+ "!And" ,
973+ "!Or" ,
974+ "!Not" ,
975+ "!If" ,
976+ "!Condition" ,
977+ ]
978+
979+ for func in cf_functions :
980+ CFLoader .add_constructor (func , construct_unknown )
981+
937982 with open (template_path , "r" , encoding = "utf-8" ) as f :
938- lines = f . readlines ( )
983+ template = yaml . load ( f , Loader = CFLoader )
939984
940- for i , line in enumerate (lines ):
941- # Look for CodeUri that matches our directory
942- if "CodeUri:" in line :
943- code_uri = (
944- line .split ("CodeUri:" )[- 1 ].strip ().strip ("\" '" ).rstrip ("/" )
945- )
946- code_dir = code_uri .split ("/" )[- 1 ] if "/" in code_uri else code_uri
947-
948- if code_dir == dir_name :
949- # Found matching CodeUri, now look backwards for the resource name
950- # Look for AWS::Serverless::Function type first
951- for j in range (i - 1 , max (0 , i - 50 ), - 1 ):
952- if "Type: AWS::Serverless::Function" in lines [j ]:
953- # Found the function type, now look backwards for resource name
954- for k in range (j - 1 , max (0 , j - 10 ), - 1 ):
955- stripped = lines [k ].strip ()
956- # Resource names are at the start of line and end with ':'
957- if (
958- stripped
959- and not stripped .startswith (" " )
960- and stripped .endswith (":" )
961- ):
962- return stripped .rstrip (":" )
963- break
964-
965- return dir_name
985+ if not template or not isinstance (template , dict ):
986+ raise Exception (f"Failed to parse YAML template: { template_path } " )
987+
988+ resources = template .get ("Resources" , {})
989+ for resource_name , resource_config in resources .items ():
990+ if (
991+ resource_config
992+ and isinstance (resource_config , dict )
993+ and resource_config .get ("Type" ) == "AWS::Serverless::Function"
994+ ):
995+ properties = resource_config .get ("Properties" , {})
996+ if properties and isinstance (properties , dict ):
997+ code_uri = properties .get ("CodeUri" , "" )
998+ if isinstance (code_uri , str ):
999+ code_uri = code_uri .rstrip ("/" )
1000+ code_dir = (
1001+ code_uri .split ("/" )[- 1 ] if "/" in code_uri else code_uri
1002+ )
1003+ if code_dir == dir_name :
1004+ return resource_name
1005+ raise Exception (
1006+ f"No CloudFormation function found for directory { dir_name } in template { template_path } "
1007+ )
9661008
9671009 except Exception as e :
9681010 self .console .print (
0 commit comments