1+ function success = execute(hook_name , spec , logger )
2+ % Execute platform-specific hooks from spec.json
3+ %
4+ % Parameters:
5+ % hook_name (string): Name of the hook to execute ('pre_install', 'post_install', 'environment_setup')
6+ % spec (struct): Specification structure from spec.json
7+ % logger (struct): Logger instance
8+ %
9+ % Returns:
10+ % success (logical): True if all hook commands succeeded
11+
12+ success = true ;
13+
14+ % Check if hooks section exists
15+ if ~isfield(spec , ' hooks' )
16+ logger .debug(' No hooks section found in spec' );
17+ return ;
18+ end
19+
20+ % Check if specific hook exists
21+ if ~isfield(spec .hooks, hook_name )
22+ logger .debug(' Hook "%s " not found in spec.hooks' , hook_name );
23+ return ;
24+ end
25+
26+ % Determine platform
27+ platform = mhkit .sys.get_platform();
28+ hook_section = spec .hooks.(hook_name );
29+
30+ logger .info(' Executing %s hooks for platform "%s "...' , hook_name , platform );
31+
32+ % Execute environment variables first
33+ if isfield(hook_section , ' environment_variables' )
34+ success = execute_environment_variables(hook_section .environment_variables, platform , spec , logger );
35+ if ~success
36+ logger .error(' Environment variable setup failed' );
37+ return ;
38+ end
39+ end
40+
41+ % Execute commands
42+ if isfield(hook_section , ' commands' )
43+ success = execute_commands(hook_section .commands, platform , spec , logger );
44+ if ~success
45+ logger .error(' Command execution failed' );
46+ return ;
47+ end
48+ end
49+
50+ logger .info(' Successfully completed %s hooks for platform "%s "' , hook_name , platform );
51+ end
52+
53+ function success = execute_environment_variables(env_vars_section , platform , spec , logger )
54+ % Execute environment variable setup for a platform
55+ %
56+ % Parameters:
57+ % env_vars_section (struct): Environment variables section from spec
58+ % platform (string): Target platform
59+ % spec (struct): Specification structure
60+ % logger (struct): Logger instance
61+ %
62+ % Returns:
63+ % success (logical): True if all environment variables were set
64+
65+ success = true ;
66+
67+ % Check if platform-specific environment variables exist
68+ if ~isfield(env_vars_section , platform )
69+ logger .debug(' No environment variables found for platform "%s "' , platform );
70+ return ;
71+ end
72+
73+ platform_env_vars = env_vars_section.(platform );
74+
75+ % Skip if empty
76+ if isempty(platform_env_vars ) || (isstruct(platform_env_vars ) && isempty(fieldnames(platform_env_vars )))
77+ logger .debug(' No environment variables to set for platform "%s "' , platform );
78+ return ;
79+ end
80+
81+ % Set each environment variable
82+ var_names = fieldnames(platform_env_vars );
83+ for i = 1 : length(var_names )
84+ var_name = var_names{i };
85+ var_value = platform_env_vars.(var_name );
86+
87+ % Perform variable substitution
88+ processed_value = substitute_variables(var_value , spec );
89+
90+ logger .debug(' Setting environment variable: %s =%s ' , var_name , processed_value );
91+
92+ try
93+ setenv(var_name , processed_value );
94+ logger .info(' Set environment variable: %s =%s ' , var_name , processed_value );
95+ catch ME
96+ logger .error(' Failed to set environment variable %s : %s ' , var_name , ME .message);
97+ success = false ;
98+ return ;
99+ end
100+ end
101+ end
102+
103+ function success = execute_commands(commands_section , platform , spec , logger )
104+ % Execute shell commands for a platform
105+ %
106+ % Parameters:
107+ % commands_section (struct): Commands section from spec
108+ % platform (string): Target platform
109+ % spec (struct): Specification structure
110+ % logger (struct): Logger instance
111+ %
112+ % Returns:
113+ % success (logical): True if all commands succeeded
114+
115+ success = true ;
116+
117+ % Check if platform-specific commands exist
118+ if ~isfield(commands_section , platform )
119+ logger .debug(' No commands found for platform "%s "' , platform );
120+ return ;
121+ end
122+
123+ platform_commands = commands_section.(platform );
124+
125+ % Skip if empty
126+ if isempty(platform_commands )
127+ logger .debug(' No commands to execute for platform "%s "' , platform );
128+ return ;
129+ end
130+
131+ % Execute each command
132+ for i = 1 : length(platform_commands )
133+ command = platform_commands{i };
134+ success = execute_single_command(command , spec , logger );
135+ if ~success
136+ logger .error(' Command failed: %s ' , command );
137+ return ;
138+ end
139+ end
140+ end
141+
142+ function success = execute_single_command(command , spec , logger )
143+ % Execute a single command with variable substitution
144+ %
145+ % Parameters:
146+ % command (string): Command to execute
147+ % spec (struct): Specification structure for variable substitution
148+ % logger (struct): Logger instance
149+ %
150+ % Returns:
151+ % success (logical): True if command succeeded
152+
153+ % Perform variable substitution
154+ processed_command = substitute_variables(command , spec );
155+
156+ logger .debug(' Executing command: %s ' , processed_command );
157+
158+ % Execute command
159+ [status , result ] = mhkit .sys(processed_command );
160+
161+ if status == 0
162+ logger .debug(' Command succeeded: %s ' , processed_command );
163+ success = true ;
164+ else
165+ logger .error(' Command failed with status %d : %s ' , status , processed_command );
166+ if ~isempty(result )
167+ logger .error(' Error output: %s ' , result );
168+ end
169+ success = false ;
170+ end
171+ end
172+
173+ function result = substitute_variables(text , spec )
174+ % Substitute variables in text using spec values
175+ %
176+ % Parameters:
177+ % text (string): Text with variables to substitute
178+ % spec (struct): Specification structure
179+ %
180+ % Returns:
181+ % result (string): Text with variables substituted
182+
183+ result = text ;
184+
185+ % Standard substitutions
186+ if contains(result , ' <conda_env>' )
187+ result = strrep(result , ' <conda_env>' , spec .conda.environment_name);
188+ end
189+
190+ if contains(result , ' <python_version>' )
191+ result = strrep(result , ' <python_version>' , spec .python.install_version);
192+ end
193+
194+ if contains(result , ' <mhkit_python_version>' )
195+ result = strrep(result , ' <mhkit_python_version>' , spec .mhkit_python.version);
196+ end
197+
198+ % Platform-specific substitutions
199+ if contains(result , ' <conda_lib_path>' )
200+ % Get conda library path dynamically
201+ conda_env = spec .conda.environment_name;
202+ [status , conda_info ] = mhkit .sys(sprintf(' conda run -n %s python -c "import sys; import os; print(os.path.join(os.path.dirname(sys.executable), '' lib'' ))"' , conda_env ));
203+ if status == 0
204+ conda_lib_path = strtrim(conda_info );
205+ result = strrep(result , ' <conda_lib_path>' , conda_lib_path );
206+ end
207+ end
208+ end
0 commit comments