1+ import argparse
2+ import logging
3+ import os
4+ import platform
5+ import requests
6+ import shutil
7+ import subprocess
8+ import json
9+
10+
11+ USD_COMPILED_DOWNLOAD_URL = {
12+ "25.05" : {
13+ "Windows" : "https://developer.nvidia.com/downloads/USD/usd_binaries/25.05/usd.py311.windows-x86_64.usdview.release-0.25.05-25f3d3d8.zip" ,
14+ "Linux" : "https://developer.nvidia.com/downloads/USD/usd_binaries/25.05/usd.py311.manylinux_2_35_x86_64.usdview.release@0.25.05-25f3d3d8.zip"
15+ },
16+ "24.11" : {
17+ "Windows" : "https://developer.nvidia.com/downloads/USD/usd_binaries/24.11/usd.py311.windows-x86_64.usdview.release-0.24.11-4d81dd85.zip" ,
18+ "Linux" : "https://developer.nvidia.com/downloads/USD/usd_binaries/24.11/usd.py311.manylinux_2_35_x86_64.usdview.release-0.24.11-4d81dd85.zip"
19+ }
20+ }
21+ SEVENZIP_WINDOWS_DOWNLOAD_URL = {
22+ "2301" : "https://www.7-zip.org/a/7z2401-x64.exe"
23+ }
24+
25+
26+ logging .basicConfig (format = "%(asctime)s %(message)s" , datefmt = "%m/%d/%Y %I:%M:%S %p" , level = logging .INFO )
27+
28+
29+ def download_file (download_file_path , download_url ):
30+ """Download the release to the directory
31+ Args:
32+ download_file_path (str): The target file
33+ download_url (str): The download url
34+ Returns:
35+ str: The file path of the downloaded file
36+ """
37+ # Download file
38+ download_dir_path = os .path .dirname (download_file_path )
39+ if not os .path .exists (download_dir_path ):
40+ os .makedirs (download_dir_path )
41+ request = requests .get (download_url , stream = True )
42+ if request .status_code == 200 :
43+ with open (download_file_path , "wb" ) as download_file :
44+ request .raw .decode_content = True
45+ shutil .copyfileobj (request .raw , download_file )
46+ else :
47+ raise Exception ("Error downloading file | {}" .format (download_url ))
48+ return download_file_path
49+
50+
51+ def get_standalone_platform ():
52+ """Get the active platform usable for SideFX platform API calls
53+ Returns:
54+ str: The active platform
55+ """
56+ current_platform = platform .system ()
57+ if current_platform == "Windows" or current_platform .startswith ("CYGWIN" ):
58+ return "Windows"
59+ elif current_platform == "Linux" :
60+ return "Linux"
61+ raise Exception (f"Platform not supported: { current_platform } " )
62+
63+
64+ def install_standalone_product (product , version , dependency_dir_path ):
65+ """Install a standalone USD release
66+ Args:
67+ version (str|None): The target product version (e.g. 2024.4, etc.)
68+ dependency_dir_path (str): The install dir path.
69+ """
70+
71+ # Directories
72+ download_dir_path = os .path .join (dependency_dir_path , "download" )
73+ install_dir_path = os .path .join (dependency_dir_path , "install" )
74+ if os .path .exists (download_dir_path ):
75+ shutil .rmtree (download_dir_path )
76+ if os .path .exists (install_dir_path ):
77+ shutil .rmtree (install_dir_path )
78+ os .makedirs (download_dir_path )
79+ os .makedirs (install_dir_path )
80+
81+ sevenZip_dir_name = "7zip"
82+ sevenZip_download_dir_path = os .path .join (download_dir_path , sevenZip_dir_name )
83+ sevenZip_install_dir_path = os .path .join (install_dir_path , sevenZip_dir_name )
84+
85+ usd_standalone_dir_name = "usd_standalone"
86+ usd_standalone_download_dir_path = os .path .join (download_dir_path , usd_standalone_dir_name )
87+ usd_standalone_install_dir_path = os .path .join (install_dir_path , usd_standalone_dir_name )
88+
89+ config_file_path = os .path .join (install_dir_path , "config.json" )
90+
91+ standalone_platform = get_standalone_platform ()
92+
93+ # USD
94+ usd_standalone_download_url = USD_COMPILED_DOWNLOAD_URL [version ][standalone_platform ]
95+ usd_standalone_download_file_path = os .path .join (usd_standalone_download_dir_path , "usd_standalone.zip" )
96+ logging .info ("Downloading USD Build {}" .format (version ))
97+ download_file (usd_standalone_download_file_path , usd_standalone_download_url )
98+ logging .info ("Extracting USD Build" )
99+ if standalone_platform == "Windows" :
100+ # 7Zip
101+ serverZip_version = "2301"
102+ serverZip_download_url = SEVENZIP_WINDOWS_DOWNLOAD_URL [serverZip_version ]
103+ serverZip_download_file_path = os .path .join (sevenZip_download_dir_path , "7zip.exe" )
104+ logging .info ("Downloading 7zip (Build {})" .format (serverZip_version ))
105+ download_file (serverZip_download_file_path , serverZip_download_url )
106+ logging .info ("Installing 7zip" )
107+ command = [serverZip_download_file_path , "/S" , "/D={}" .format (sevenZip_install_dir_path )]
108+ process = subprocess .check_call (command , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
109+ serverZip_exe_file_path = os .path .join (sevenZip_install_dir_path , "7z.exe" )
110+ # Unzip
111+ command = [serverZip_exe_file_path , "x" , usd_standalone_download_file_path , "-o{}" .format (usd_standalone_install_dir_path )]
112+ process = subprocess .check_call (command , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
113+ elif standalone_platform == "Linux" :
114+ # Unzip
115+ command = ["7z" , "x" , f"-o{ usd_standalone_install_dir_path } " , usd_standalone_download_file_path ]
116+ process = subprocess .check_call (command , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
117+
118+ # Store configuration
119+ python_version = os .path .basename (usd_standalone_download_url ).split ("." )[1 ]
120+ with open (config_file_path , "w" ) as config_file :
121+ config = {
122+ "python" : python_version ,
123+ "usd" : version ,
124+ }
125+ json .dump (config , config_file )
126+
127+
128+ def create_standalone_artifact (artifact_src , artifact_dst , artifact_prefix , artifact_product_name , dependency_dir_path ):
129+ """Create a .zip artifact based on the source directory content.
130+ The output name will have will end in the houdini build name.
131+
132+ Args:
133+ artifact_src (str): The source directory
134+ artifact_dst (str): The target directory
135+ artifact_prefix (str): The file name prefix, the suffix will be the Houdini build name
136+ artifact_product_name (str): The file name product name.
137+ This defines the Maya product name, e.g. like 'maya'
138+ dependency_dir_path (str): The dependency install directory path.
139+ Returns:
140+ str: The artifact file path
141+ """
142+ install_dir_path = os .path .join (dependency_dir_path , "install" )
143+ config_file_path = os .path .join (install_dir_path , "config.json" )
144+ with open (config_file_path , "r" ) as config_file :
145+ config = json .load (config_file )
146+
147+ usd_version = config ["usd" ]
148+ python_version = config ["python" ]
149+ standalone_platform = get_standalone_platform ()
150+ artifact_file_path = os .path .join (
151+ artifact_dst , f"{ artifact_prefix } _{ artifact_product_name } -{ usd_version } -{ python_version } -{ standalone_platform } "
152+ )
153+ artifact_dir_path = os .path .dirname (artifact_file_path )
154+ if not os .path .exists (artifact_dir_path ):
155+ os .makedirs (artifact_dir_path )
156+ shutil .make_archive (artifact_file_path , "zip" , artifact_src )
157+
158+
159+ if __name__ == "__main__" :
160+ # Parse args
161+ parser = argparse .ArgumentParser ()
162+ parser .add_argument ("--install" , action = "store_true" , help = "Install the standalone pre-compiled USD build" )
163+ parser .add_argument (
164+ "--install_standalone_product_name" ,
165+ help = "Standalone product name to install. If not provided, fallback to the default." ,
166+ )
167+ parser .add_argument (
168+ "--install_standalone_product_version" ,
169+ help = "USD product version to install." ,
170+ )
171+ parser .add_argument (
172+ "--install_directory" ,
173+ help = "The installation directory." ,
174+ )
175+ parser .add_argument ("--artifact" , action = "store_true" , help = "Create artifact" )
176+ parser .add_argument ("--artifact_src" , help = "Artifact source directory" )
177+ parser .add_argument ("--artifact_dst" , help = "Artifact target directory" )
178+ parser .add_argument ("--artifact_prefix" , help = "Artifact name prefix" )
179+ parser .add_argument ("--artifact_product_name" , help = "Artifact product name" )
180+ args = parser .parse_args ()
181+ # Execute
182+ # Install precompiled standalone USD with headers
183+ if args .install :
184+ install_standalone_product (
185+ args .install_standalone_product_name ,
186+ args .install_standalone_product_version ,
187+ args .install_directory
188+ )
189+ # Create artifact tagged with stand build name (expects standalone USD build to be installed via the above install command)
190+ if args .artifact :
191+ create_standalone_artifact (
192+ args .artifact_src , args .artifact_dst , args .artifact_prefix , args .artifact_product_name , args .install_directory
193+ )
0 commit comments