11import argparse
2- import hashlib
32import logging
43import os
54import pathlib
65import platform
76import re
8- import requests
97import shutil
10- import sidefx
8+ import stat
119import subprocess
12- import tarfile
10+ from typing import Literal
1311
12+ import requests
13+ import sidefx
1414
1515SIDEFX_CLIENT_ID = os .environ .get ("SIDEFX_CLIENT_ID" , "" )
1616SIDEFX_CLIENT_SECRET_KEY = os .environ .get ("SIDEFX_CLIENT_SECRET_KEY" , "" )
1919logging .basicConfig (format = "%(asctime)s %(message)s" , datefmt = "%m/%d/%Y %I:%M:%S %p" )
2020
2121
22- def create_sidefx_service (client_id , client_secret_key ):
22+ def create_sidefx_service (client_id : str , client_secret_key : str ):
2323 """Get the SideFX API service
2424 Args:
2525 client_id (str): The client id
@@ -35,7 +35,7 @@ def create_sidefx_service(client_id, client_secret_key):
3535 )
3636
3737
38- def get_sidefx_platform ():
38+ def get_sidefx_platform () -> Literal [ "win64" ] | Literal [ "macos" ] | Literal [ "linux" ] :
3939 """Get the active platform usable for SideFX platform API calls
4040 Returns:
4141 str: The active platform
@@ -50,8 +50,7 @@ def get_sidefx_platform():
5050 raise Exception (f"Platform not supported: { current_platform } " )
5151
5252
53-
54- def download_sidefx_product_release (dir_path , release ):
53+ def download_sidefx_product_release (dir_path : str , release : dict ) -> str :
5554 """Download the release to the directory
5655 Args:
5756 dir_path (str): The target directory
@@ -77,15 +76,31 @@ def download_sidefx_product_release(dir_path, release):
7776 # download_file_hash.update(chunk)
7877 # if download_file_hash.hexdigest() != release["hash"]:
7978 # raise Exception("Checksum does not match!")
79+ os .chmod (
80+ download_file_path ,
81+ stat .ST_MODE
82+ | stat .S_IEXEC
83+ | stat .S_IXUSR
84+ | stat .S_IXGRP
85+ | stat .S_IRUSR
86+ | stat .S_IRGRP ,
87+ )
88+
8089 return download_file_path
8190
8291
83- def install_sidefx_product (product , version ) :
92+ def install_sidefx_product (product : str , version : str ) -> None :
8493 """Install a production release of Houdini
8594 Args:
8695 product (str): The target product name (e.g. houdini, houdini-py39, etc.)
8796 version (str|None): The target product version (e.g. 20.0, 19.5, etc.)
8897 """
98+
99+ # Create downloads directory
100+ downloads_dir_path = os .path .join (os .path .expanduser ("~" ), "Downloads" )
101+ if not os .path .isdir (downloads_dir_path ):
102+ os .makedirs (downloads_dir_path )
103+
89104 # Connect to SideFX API
90105 logging .info ("Connecting to SideFX API" )
91106 sidefx_service = create_sidefx_service (SIDEFX_CLIENT_ID , SIDEFX_CLIENT_SECRET_KEY )
@@ -119,61 +134,83 @@ def install_sidefx_product(product, version):
119134 "No Houdini version found for requested version | {}" .format (version )
120135 )
121136
122- target_release_download = sidefx_service .download .get_daily_build_download (
123- product = target_release ["product" ],
124- version = target_release ["version" ],
125- build = target_release ["build" ],
126- platform = target_release ["platform" ],
137+ # Install Houdini through launcher
138+ logging .info ("Downloading Houdini Launcher" )
139+
140+ houdini_launcher_releases_list = sidefx_service .download .get_daily_builds_list (
141+ product = "houdini-launcher" ,
142+ version = None ,
143+ platform = sidefx_platform ,
144+ only_production = True ,
127145 )
146+ if not houdini_launcher_releases_list :
147+ raise Exception ("No 'houdini-launcher' releases found!" )
128148
129- # Download latest production release
130- logging .info (
131- "Downloading Houdini build {version}.{build}" .format (
132- version = target_release ["version" ], build = target_release ["build" ]
149+ houdini_launcher_target_release = houdini_launcher_releases_list [0 ]
150+ houdini_launcher_target_release_download = (
151+ sidefx_service .download .get_daily_build_download (
152+ product = houdini_launcher_target_release ["product" ],
153+ version = houdini_launcher_target_release ["version" ],
154+ build = houdini_launcher_target_release ["build" ],
155+ platform = houdini_launcher_target_release ["platform" ],
133156 )
134157 )
135- downloads_dir_path = os .path .join (os .path .expanduser ("~" ), "Downloads" )
136- if not os .path .isdir (downloads_dir_path ):
137- os .makedirs (downloads_dir_path )
138- houdini_installer_file_path = download_sidefx_product_release (
139- downloads_dir_path , target_release_download
158+
159+ houdini_launcher_installer_file_path = download_sidefx_product_release (
160+ downloads_dir_path , houdini_launcher_target_release_download
140161 )
141- # Install latest production release
142- logging .info (
143- "Installing Houdini build {version}.{build}" .format (
144- version = target_release ["version" ], build = target_release ["build" ]
162+
163+ license_file_path = os .path .join (downloads_dir_path , "sidefx_settings.ini" )
164+ with open (license_file_path , "w" ) as license_file :
165+ license_file .write (
166+ f"client_id={ SIDEFX_CLIENT_ID } \n client_secret={ SIDEFX_CLIENT_SECRET_KEY } \n "
167+ )
168+
169+ # Currently the API and the installer consume different syntaxes for product and build option
170+ cmd_flags = ["install" ]
171+ if "-" in target_release ["product" ]:
172+ target_release_product , target_release_build_type = target_release [
173+ "product"
174+ ].split ("-" )
175+ cmd_flags .extend (
176+ [
177+ "--product" ,
178+ target_release_product ,
179+ "--build-option" ,
180+ target_release_build_type ,
181+ ]
145182 )
183+ else :
184+ cmd_flags .extend (["--product" , target_release ["product" ]])
185+ cmd_flags .extend (
186+ [
187+ "--version" ,
188+ f"{ target_release ['version' ]} .{ target_release ['build' ]} " ,
189+ "--platform" ,
190+ target_release ["platform" ],
191+ "--settings-file" ,
192+ license_file_path ,
193+ "--accept-EULA" ,
194+ "SideFX-2021-10-13" ,
195+ ]
146196 )
147197 hfs_dir_path = ""
148198 if sidefx_platform == "linux" :
149- # Unpack tar file
150- with tarfile .open (houdini_installer_file_path ) as tar_file :
151- tar_file .extractall (downloads_dir_path )
152- os .remove (houdini_installer_file_path )
153- # Get folder name
154- houdini_installer_dir_name = target_release_download ["filename" ]
155- houdini_installer_dir_name = houdini_installer_dir_name .replace (".tar" , "" )
156- houdini_installer_dir_name = houdini_installer_dir_name .replace (".gz" , "" )
157- houdini_installer_dir_path = os .path .join (
158- downloads_dir_path , houdini_installer_dir_name
199+ cmd = [houdini_launcher_installer_file_path ]
200+ status = subprocess .run (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
201+ if status .returncode != 0 :
202+ raise Exception (
203+ "Failed to install Houdini Launcher, ran into the following error:\n {error}" .format (
204+ error = status .stderr
205+ )
206+ )
207+ logging .info (
208+ "Installing Houdini build {version}.{build}" .format (
209+ version = target_release ["version" ], build = target_release ["build" ]
210+ )
159211 )
160- cmd = [
161- os .path .join (houdini_installer_dir_path , "houdini.install" ),
162- "--auto-install" ,
163- "--accept-EULA" ,
164- "2021-10-13" ,
165- "--install-houdini" ,
166- "--no-install-license" ,
167- "--no-install-avahi" ,
168- "--no-install-hqueue-server" ,
169- "--no-install-hqueue-client" ,
170- "--no-install-menus" ,
171- "--no-install-bin-symlink" ,
172- "--no-install-engine-maya" ,
173- "--no-install-engine-unity" ,
174- "--no-install-engine-unreal" ,
175- "--no-install-sidefxlabs" ,
176- ]
212+ cmd = ["/opt/sidefx/launcher/bin/houdini_installer" ]
213+ cmd .extend (cmd_flags )
177214 status = subprocess .run (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
178215 if status .returncode != 0 :
179216 raise Exception (
@@ -187,21 +224,24 @@ def install_sidefx_product(product, version):
187224 )
188225 hfs_symlink_dir_path = os .path .join (os .path .dirname (hfs_dir_path ), "hfs" )
189226 elif sidefx_platform == "win64" :
190- cmd = [
191- houdini_installer_file_path ,
192- "/S" ,
193- "/AcceptEULA=2021-10-13" ,
194- "/MainApp" ,
195- "/LicenseServer=No" ,
196- "/StartMenu=No" ,
197- "/HQueueServer=No" ,
198- "/HQueueClient=No" ,
199- "/EngineMaya=No" ,
200- "/Engine3dsMax" ,
201- "/EngineUnity" ,
202- "/EngineUnreal=No" ,
203- "/SideFXLabs=No" ,
204- ]
227+ status = subprocess .run (
228+ [houdini_launcher_installer_file_path , "/S" ],
229+ stdout = subprocess .PIPE ,
230+ stderr = subprocess .PIPE ,
231+ )
232+ if status .returncode != 0 :
233+ raise Exception (
234+ "Failed to install Houdini Launcher, ran into the following error:\n {error}" .format (
235+ error = status .stderr
236+ )
237+ )
238+ logging .info (
239+ "Installing Houdini build {version}.{build}" .format (
240+ version = target_release ["version" ], build = target_release ["build" ]
241+ )
242+ )
243+ cmd = [r"C:\Program Files\SideFX\launcher\bin\houdini_installer.exe" ]
244+ cmd .extend (cmd_flags )
205245 status = subprocess .run (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
206246 if status .returncode != 0 :
207247 raise Exception (
@@ -210,16 +250,13 @@ def install_sidefx_product(product, version):
210250 )
211251 )
212252 hfs_dir_path = os .path .join (
213- "C:\Program Files\Side Effects Software" ,
253+ r "C:\Program Files\Side Effects Software" ,
214254 "Houdini {}.{}" .format (target_release ["version" ], target_release ["build" ]),
215255 )
216- hfs_symlink_dir_path = os .path .join (
217- os .path .dirname (hfs_dir_path ), "Houdini"
218- )
256+ hfs_symlink_dir_path = os .path .join (os .path .dirname (hfs_dir_path ), "Houdini" )
219257 else :
220258 raise Exception (
221- "Platform {platform} is currently not"
222- "supported!" .format (platform = platform )
259+ "Platform {platform} is currently not supported!" .format (platform = platform )
223260 )
224261 # Create version-less symlink
225262 logging .info (
@@ -230,15 +267,20 @@ def install_sidefx_product(product, version):
230267 os .symlink (hfs_dir_path , hfs_symlink_dir_path )
231268
232269
233- def create_sidefx_houdini_artifact (artifact_src , artifact_dst , artifact_prefix , artifact_product_name ):
270+ def create_sidefx_houdini_artifact (
271+ artifact_src : str ,
272+ artifact_dst : str ,
273+ artifact_prefix : str ,
274+ artifact_product_name : str ,
275+ ) -> None :
234276 """Create a .zip artifact based on the source directory content.
235277 The output name will have will end in the houdini build name.
236278
237279 Args:
238280 artifact_src (str): The source directory
239281 artifact_dst (str): The target directory
240282 artifact_prefix (str): The file name prefix, the suffix will be the Houdini build name
241- artifact_product_name (str): The file name product name.
283+ artifact_product_name (str): The file name product name.
242284 This defines the Houdini product name, e.g. like 'houdini-py39'
243285 Returns:
244286 str: The artifact file path
@@ -249,16 +291,16 @@ def create_sidefx_houdini_artifact(artifact_src, artifact_dst, artifact_prefix,
249291 hfs_build_name = os .path .basename (pathlib .Path ("/opt/hfs" ).resolve ())
250292 elif sidefx_platform == "win64" :
251293 hfs_build_name = os .path .basename (
252- pathlib .Path ("C:\Program Files\Side Effects Software\Houdini" ).resolve ()
294+ pathlib .Path (r "C:\Program Files\Side Effects Software\Houdini" ).resolve ()
253295 )
254296 else :
255297 raise Exception (
256- "Platform {platform} is currently not"
257- "supported!" .format (platform = platform )
298+ "Platform {platform} is currently notsupported!" .format (platform = platform )
258299 )
259300 hfs_build_name = re_digitdot .sub ("" , hfs_build_name )
260301 artifact_file_path = os .path .join (
261- artifact_dst , f"{ artifact_prefix } _{ artifact_product_name } -{ hfs_build_name } -{ sidefx_platform } "
302+ artifact_dst ,
303+ f"{ artifact_prefix } _{ artifact_product_name } -{ hfs_build_name } -{ sidefx_platform } " ,
262304 )
263305 artifact_dir_path = os .path .dirname (artifact_file_path )
264306 if not os .path .exists (artifact_dir_path ):
@@ -287,10 +329,14 @@ def create_sidefx_houdini_artifact(artifact_src, artifact_dst, artifact_prefix,
287329 # Execute
288330 # Install Houdini
289331 if args .install :
290- install_sidefx_product (args .install_houdini_product_name ,
291- args .install_houdini_product_version )
332+ install_sidefx_product (
333+ args .install_houdini_product_name , args .install_houdini_product_version
334+ )
292335 # Create artifact tagged with Houdini build name (expects Houdini to be installed via the above install command)
293336 if args .artifact :
294337 create_sidefx_houdini_artifact (
295- args .artifact_src , args .artifact_dst , args .artifact_prefix , args .artifact_product_name
338+ args .artifact_src ,
339+ args .artifact_dst ,
340+ args .artifact_prefix ,
341+ args .artifact_product_name ,
296342 )
0 commit comments