66
77set -euo pipefail
88
9- # Variables from Terraform template
109EXTENSIONS=" ${EXTENSIONS} "
1110EXTENSIONS_URLS=" ${EXTENSIONS_URLS} "
1211EXTENSIONS_DIR=" ${EXTENSIONS_DIR} "
1312IDE_TYPE=" ${IDE_TYPE} "
14-
15- # Color constants
1613BOLD=' \033[0;1m'
1714CODE=' \033[36;40;1m'
1815GREEN=' \033[0;32m'
1916YELLOW=' \033[1;33m'
2017RED=' \033[0;31m'
2118RESET=' \033[0m'
2219
23- # Check if extension is already installed
2420is_extension_installed () {
2521 local target_dir=" $1 "
2622 local extension_id=" $2 "
2723 local extension_dir=" $target_dir /$extension_id "
2824
29- if [ -d " $extension_dir " ] && [ -f " $extension_dir /package.json" ]; then
30- if grep -q ' "name"' " $extension_dir /package.json" 2> /dev/null; then
31- if grep -q ' "publisher"' " $extension_dir /package.json" 2> /dev/null; then
25+ local package_json=" "
26+ if [ -f " $extension_dir /package.json" ]; then
27+ package_json=" $extension_dir /package.json"
28+ elif [ -f " $extension_dir /extension/package.json" ]; then
29+ package_json=" $extension_dir /extension/package.json"
30+ fi
31+
32+ if [ -d " $extension_dir " ] && [ -n " $package_json " ]; then
33+ if grep -q ' "name"' " $package_json " 2> /dev/null; then
34+ if grep -q ' "publisher"' " $package_json " 2> /dev/null; then
3235 return 0
3336 fi
3437 fi
3538 fi
3639 return 1
3740}
3841
39- # Generate marketplace URL for extension
4042generate_extension_url () {
4143 local extension_id=" $1 "
4244
4345 if [[ -z " $extension_id " ]]; then
4446 return 1
4547 fi
4648
47- # Extract publisher and extension name
4849 local publisher
4950 publisher=$( echo " $extension_id " | cut -d' .' -f1)
5051 local name
@@ -55,32 +56,26 @@ generate_extension_url() {
5556 return 1
5657 fi
5758
58- # Generate URL based on IDE type
5959 case " ${IDE_TYPE} " in
6060 " vscode" | " vscode-insiders" )
61- # Microsoft IDEs: Use the VS Code API to get metadata
6261 printf " https://marketplace.visualstudio.com/_apis/public/gallery/vscode/%s/%s/latest" " $publisher " " $name "
6362 ;;
6463 " vscodium" | " cursor" | " windsurf" | " kiro" )
65- # Non-Microsoft IDEs: Use Open VSX Registry metadata endpoint
6664 printf " https://open-vsx.org/api/%s/%s/latest" " $publisher " " $name "
6765 ;;
6866 * )
69- # Default: Use Open VSX Registry for unknown IDEs
7067 printf " https://open-vsx.org/api/%s/%s/latest" " $publisher " " $name "
7168 ;;
7269 esac
7370}
7471
75- # Download and install extension
7672download_and_install_extension () {
7773 local target_dir=" $1 "
7874 local extension_id=" $2 "
7975 local metadata_url=" $3 "
8076 local temp_dir=" $4 "
8177 local log_file=" $5 "
8278
83- # Check if already installed (idempotency)
8479 if is_extension_installed " $target_dir " " $extension_id " ; then
8580 printf " $$ {GREEN}✓ Extension $$ {CODE}$extension_id $$ {RESET}$$ {GREEN} already installed$$ {RESET}\n"
8681 return 0
@@ -89,57 +84,47 @@ download_and_install_extension() {
8984 printf " $$ {BOLD}📦 Installing extension $$ {CODE}$extension_id $$ {RESET}...\n"
9085 echo " $( date) : Starting installation of $extension_id " >> " $log_file "
9186
92- # Use dedicated temp directory for this extension
9387 local extension_temp_dir
9488 extension_temp_dir=" $temp_dir /$extension_id -$( date +%s) "
9589 local download_file=" $temp_dir /$extension_id .vsix"
9690
97- # First, get the metadata JSON
9891 echo " $( date) : Fetching metadata from $metadata_url " >> " $log_file "
9992 local metadata_response
10093 if metadata_response=$( timeout 30 curl -fsSL " $metadata_url " 2>&1 ) ; then
101- # Extract the download URL from JSON (handle both VS Code and Open VSX)
10294 local download_url
10395 if [[ " ${IDE_TYPE} " == " vscode" || " ${IDE_TYPE} " == " vscode-insiders" ]]; then
104- # VS Code format
10596 download_url=$( echo " $metadata_response " | jq -r ' .versions[0].files[] | select(.assetType == "Microsoft.VisualStudio.Services.VSIXPackage") | .source' 2> /dev/null)
10697 else
107- # Open VSX format
10898 download_url=$( echo " $metadata_response " | jq -r ' .files.download // .downloads.universal // empty' 2> /dev/null)
10999 fi
110100
111101 if [[ -n " $download_url " && " $download_url " != " null" ]]; then
112102 echo " $( date) : Extracted download URL: $download_url " >> " $log_file "
113- # Download the actual .vsix file
114103 echo " $( date) : Downloading extension to $download_file " >> " $log_file "
115104 if timeout 30 curl -fsSL " $download_url " -o " $download_file " 2>&1 ; then
116105 echo " $( date) : File size: $( stat -c%s " $download_file " ) bytes" >> " $log_file "
117- # Verify the download is a valid ZIP file
118106 echo " $( date) : Validating ZIP file..." >> " $log_file "
119107 if unzip -t " $download_file " > /dev/null 2>&1 ; then
120- # Create target directory
121108 mkdir -p " $target_dir "
122109 local extract_dir=" $target_dir /$extension_id "
123110
124- # Remove existing incomplete installation
125111 if [ -d " $extract_dir " ]; then
126112 rm -rf " $extract_dir "
127113 fi
128114
129115 mkdir -p " $extract_dir "
130116
131- # Extract extension
132117 echo " $( date) : Extracting to $extract_dir " >> " $log_file "
133118 if unzip -q " $download_file " -d " $extract_dir " 2> /dev/null; then
134- if [ -f " $extract_dir /package.json" ]; then
119+ if [ -f " $extract_dir /package.json" ] || [ -f " $extract_dir /extension/package.json " ] ; then
135120 printf " $$ {GREEN}✅ Successfully installed $$ {CODE}$extension_id $$ {RESET}\n"
136- # Log success
137121 echo " $( date) : Successfully installed $extension_id " >> " $log_file "
138122 rm -rf " $extension_temp_dir "
139123 return 0
140124 else
141125 printf " $$ {RED}❌ Invalid extension package$$ {RESET}\n"
142- echo " $( date) : Invalid extension package for $extension_id " >> " $log_file "
126+ echo " $( date) : Invalid extension package for $extension_id - package.json not found" >> " $log_file "
127+ echo " $( date) : Directory contents: $( ls -la " $extract_dir " ) " >> " $log_file "
143128 rm -rf " $extract_dir "
144129 rm -rf " $extension_temp_dir "
145130 return 1
@@ -181,7 +166,6 @@ download_and_install_extension() {
181166 fi
182167}
183168
184- # Install extension from URL
185169install_extension_from_url () {
186170 local url=" $1 "
187171 local target_dir=" $2 "
@@ -200,19 +184,16 @@ install_extension_from_url() {
200184 return 0
201185 fi
202186
203- # Use dedicated temp directory
204187 local extension_temp_dir
205188 extension_temp_dir=" $temp_dir /$extension_id -$( date +%s) "
206189 local download_file=" $temp_dir /$extension_id .vsix"
207190
208191 echo " $( date) : Downloading extension to $download_file " >> " $log_file "
209192 if timeout 30 curl -fsSL " $url " -o " $download_file " 2>&1 ; then
210193 echo " $( date) : File size: $( stat -c%s " $download_file " ) bytes" >> " $log_file "
211- # Create target directory
212194 mkdir -p " $target_dir "
213195 local extract_dir=" $target_dir /$extension_id "
214196
215- # Remove existing incomplete installation
216197 if [ -d " $extract_dir " ]; then
217198 rm -rf " $extract_dir "
218199 fi
@@ -221,14 +202,15 @@ install_extension_from_url() {
221202
222203 echo " $( date) : Extracting to $extract_dir " >> " $log_file "
223204 if unzip -q " $download_file " -d " $extract_dir " 2> /dev/null; then
224- if [ -f " $extract_dir /package.json" ]; then
205+ if [ -f " $extract_dir /package.json" ] || [ -f " $extract_dir /extension/package.json " ] ; then
225206 printf " $$ {GREEN}✅ Successfully installed $$ {CODE}$extension_id $$ {RESET}\n"
226207 echo " $( date) : Successfully installed $extension_id from URL" >> " $log_file "
227208 rm -rf " $extension_temp_dir "
228209 return 0
229210 else
230211 printf " $$ {RED}❌ Invalid extension package$$ {RESET}\n"
231- echo " $( date) : Invalid extension package for $extension_id from URL" >> " $log_file "
212+ echo " $( date) : Invalid extension package for $extension_id from URL - package.json not found" >> " $log_file "
213+ echo " $( date) : Directory contents: $( ls -la " $extract_dir " ) " >> " $log_file "
232214 rm -rf " $extract_dir "
233215 rm -rf " $extension_temp_dir "
234216 return 1
@@ -248,7 +230,6 @@ install_extension_from_url() {
248230 fi
249231}
250232
251- # Install extensions from URLs
252233install_extensions_from_urls () {
253234 local urls=" $1 "
254235 local target_dir=" $2 "
@@ -261,17 +242,14 @@ install_extensions_from_urls() {
261242
262243 printf " $$ {BOLD}🔗 Installing extensions from URLs...$$ {RESET}\n"
263244
264- # Simple approach: replace commas with newlines and process each URL
265245 echo " $urls " | tr ' ,' ' \n' | while read -r url; do
266- # Trim whitespace
267246 url=$( echo " $url " | sed ' s/^[[:space:]]*//;s/[[:space:]]*$//' )
268247 if [ -n " $url " ]; then
269248 install_extension_from_url " $url " " $target_dir " " $temp_dir " " $log_file "
270249 fi
271250 done
272251}
273252
274- # Install extensions from extension IDs
275253install_extensions_from_ids () {
276254 local extensions=" $1 "
277255 local target_dir=" $2 "
@@ -284,9 +262,7 @@ install_extensions_from_ids() {
284262
285263 printf " $$ {BOLD}🧩 Installing extensions from extension IDs...$$ {RESET}\n"
286264
287- # Simple approach: replace commas with newlines and process each extension
288265 echo " $extensions " | tr ' ,' ' \n' | while read -r extension_id; do
289- # Trim whitespace
290266 extension_id=$( echo " $extension_id " | sed ' s/^[[:space:]]*//;s/[[:space:]]*$//' )
291267 if [ -n " $extension_id " ]; then
292268 local metadata_url
@@ -301,51 +277,43 @@ install_extensions_from_ids() {
301277 done
302278}
303279
304- # Main execution
305280main () {
306281 printf " $$ {BOLD}🚀 Starting extension installation for $$ {CODE}${IDE_TYPE} $$ {RESET} IDE...\n"
307282
308- # Check dependencies
309283 for cmd in curl unzip timeout; do
310284 if ! command -v " $cmd " > /dev/null 2>&1 ; then
311285 printf " $$ {RED}❌ Missing required command: $cmd $$ {RESET}\n"
312286 return 1
313287 fi
314288 done
315289
316- # Create dedicated module directory structure
317290 local module_dir=" $HOME /.vscode-desktop-core"
318291 local temp_dir=" $module_dir /tmp"
319292 local logs_dir=" $module_dir /logs"
320293
321294 mkdir -p " $temp_dir " " $logs_dir "
322295
323- # Set up logging
324296 local log_file
325297 log_file=" $logs_dir /extension-installation-$( date +%Y%m%d-%H%M%S) .log"
326298 printf " $$ {BOLD}📝 Logging to: $$ {CODE}$log_file $$ {RESET}\n"
327299
328- # Expand tilde in extensions directory path
329300 local extensions_dir=" ${EXTENSIONS_DIR} "
330301 if [ " $$ {extensions_dir#\~}" != " $extensions_dir " ]; then
331302 extensions_dir=" $HOME /$$ {extensions_dir#\~/}"
332303 fi
333304
334305 printf " $$ {BOLD}📁 Using extensions directory: $$ {CODE}$extensions_dir $$ {RESET}\n"
335306
336- # Create extensions directory
337307 mkdir -p " $extensions_dir "
338308 if [[ ! -w " $extensions_dir " ]]; then
339309 printf " $$ {RED}❌ Extensions directory is not writable: $extensions_dir $$ {RESET}\n"
340310 return 1
341311 fi
342312
343- # Install extensions from URLs (airgapped scenario)
344313 if [ -n " ${EXTENSIONS_URLS} " ]; then
345314 install_extensions_from_urls " ${EXTENSIONS_URLS} " " $extensions_dir " " $temp_dir " " $log_file "
346315 fi
347316
348- # Install extensions from extension IDs (normal scenario)
349317 if [[ -n " ${EXTENSIONS} " ]]; then
350318 install_extensions_from_ids " ${EXTENSIONS} " " $extensions_dir " " $temp_dir " " $log_file "
351319 fi
@@ -355,7 +323,6 @@ main() {
355323 printf " $$ {BOLD}📝 Log file: $$ {CODE}$log_file $$ {RESET}\n"
356324}
357325
358- # Script execution entry point
359326if [[ -n " ${EXTENSIONS} " ]] || [[ -n " ${EXTENSIONS_URLS} " ]]; then
360327 main
361328else
0 commit comments