11#!/usr/bin/env python
22#
3- # SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
3+ # SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
44# SPDX-License-Identifier: Apache-2.0
55
66import os
2626def ESP_LOGI (x ):
2727 print ('\033 [32m{}\033 [0m' .format (x ))
2828
29+ def ESP_LOGW (x ):
30+ print ('\033 [33m{}\033 [0m' .format (x ))
31+
2932def ESP_LOGE (x ):
3033 print ('\033 [31m{}\033 [0m' .format (x ))
3134
@@ -42,7 +45,7 @@ def jihulab_repo_postprocess(path, redirect_repo):
4245 'git@jihulab.com:esp-mirror/espressif/esp-at.git' :{'preprocess' : jihulab_repo_preprocess , 'postprocess' : jihulab_repo_postprocess },
4346}
4447
45- def at_sync_submodule (path , repo , branch , commit , redirect ):
48+ def at_sync_submodule (path , repo , ref , ref_type , commit , redirect ):
4649 at_origin = subprocess .check_output (['git' , 'remote' , '-v' ]).decode (encoding = 'utf-8' ).split ()[1 ]
4750
4851 new_clone = False
@@ -53,28 +56,43 @@ def at_sync_submodule(path, repo, branch, commit, redirect):
5356 repo = '/' .join ([preset_origins [at_origin ]['preprocess' ](), os .path .basename (repo )])
5457
5558 ESP_LOGI ('Cloning into submodule:"{}" from "{}" (This may take some time)..' .format (path , repo ))
56- ret = subprocess .call ('git clone -b {} {} {}' .format (branch , repo , path ), shell = True )
59+ ret = subprocess .call ('git clone -b {} {} {}' .format (ref , repo , path ), shell = True )
5760 if ret :
5861 raise Exception ('git clone failed' )
5962 new_clone = True
6063
6164 rev_parse_head = subprocess .check_output ('cd {} && git rev-parse HEAD' .format (path ), shell = True ).decode (encoding = 'utf-8' ).strip ()
65+ need_update = False
6266 if rev_parse_head != commit :
67+ need_update = True
6368 ESP_LOGI ('Synchronizing submodule:"{}" from "{}" (This may take time)..' .format (path , repo ))
6469 print ('old commit: {}' .format (rev_parse_head ))
6570 print ('checkout commit: {}' .format (commit ))
66- cmd = 'cd {} && git fetch origin {}' .format (path , branch )
71+ if ref_type == 'tag' :
72+ cmd = 'cd {} && git fetch origin tag {}' .format (path , ref )
73+ else :
74+ cmd = 'cd {} && git fetch origin {}' .format (path , ref )
6775 ret = subprocess .call (cmd , shell = True )
6876 if ret :
6977 raise Exception ('git fetch failed! Please manually run:\r \n {}' .format (cmd ))
70- cmd = 'cd {} && git merge origin/{} {}' .format (path , branch , branch )
71- ret = subprocess .call (cmd , shell = True )
72- if ret :
73- raise Exception ('git merge failed! Please manually run:\r \n {}' .format (cmd ))
78+ if ref_type == 'branch' :
79+ cmd = 'cd {} && git merge origin/{} {}' .format (path , ref , ref )
80+ ret = subprocess .call (cmd , shell = True )
81+ if ret :
82+ raise Exception ('git merge failed! Please manually run:\r \n {}' .format (cmd ))
7483 cmd = 'cd {} && git checkout -q {}' .format (path , commit )
7584 ret = subprocess .call (cmd , shell = True )
7685 if ret :
7786 raise Exception ('git checkout failed! Please manually run:\r \n {}' .format (cmd ))
87+ else :
88+ # check if submodules are properly initialized even when commit matches
89+ try :
90+ status_output = subprocess .check_output ('cd {} && git submodule status --recursive' .format (path ),
91+ shell = True , stderr = subprocess .DEVNULL ).decode (encoding = 'utf-8' )
92+ if any (line .lstrip ().startswith ('-' ) for line in status_output .splitlines ()):
93+ need_update = True
94+ except subprocess .CalledProcessError :
95+ need_update = True
7896
7997 if new_clone :
8098 # init submodules for cloned repository
@@ -87,23 +105,53 @@ def at_sync_submodule(path, repo, branch, commit, redirect):
87105 if redirect and path == 'esp-idf' :
88106 preset_origins [at_origin ]['postprocess' ](path , None )
89107
90- if rev_parse_head != commit or new_clone :
108+ if need_update or new_clone :
109+ cmd = 'cd {} && git submodule sync' .format (path )
110+ ret = subprocess .call (cmd , shell = True )
111+ if ret :
112+ raise Exception ('git submodule sync failed! Please manually run:\r \n {}' .format (cmd ))
91113 cmd = 'cd {} && git submodule update --init --recursive' .format (path )
92114 ret = subprocess .call (cmd , shell = True )
93115 if ret :
94- raise Exception ('git submodule update failed! Please manually run:\r \n {}' .format (cmd ))
116+ ESP_LOGW ('Submodule update failed, cleaning up stale gitdir references and retrying..' )
117+ # find and remove .git files with broken gitdir references (not .git directories)
118+ for root , dirs , files in os .walk (path ):
119+ if '.git' in files :
120+ git_file = os .path .join (root , '.git' )
121+ try :
122+ with open (git_file , 'r' ) as f :
123+ content = f .read ().strip ()
124+ if content .startswith ('gitdir:' ):
125+ gitdir = content [len ('gitdir:' ):].strip ()
126+ if not os .path .isabs (gitdir ):
127+ gitdir = os .path .normpath (os .path .join (root , gitdir ))
128+ if not os .path .isdir (gitdir ):
129+ os .remove (git_file )
130+ except Exception :
131+ pass
132+ ret = subprocess .call (cmd , shell = True )
133+ if ret :
134+ raise Exception ('git submodule update failed! Please manually run:\r \n {}' .format (cmd ))
95135
96136def at_parse_idf_version (idf_ver_file , pairs ):
97137 if not os .path .exists (idf_ver_file ):
98138 ESP_LOGE ('File does not exist: {}' .format (idf_ver_file ))
99139 sys .exit (2 )
100140
141+ branch = ''
142+ tag = ''
143+ commit = ''
144+ repo = ''
101145 with open (idf_ver_file ) as f :
102146 for line in f .readlines ():
103147 index = line .strip ().find ('branch:' )
104148 if index >= 0 :
105149 branch = line [index + len ('branch:' ):].rstrip ('\n ' )
106150 continue
151+ index = line .strip ().find ('tag:' )
152+ if index >= 0 :
153+ tag = line [index + len ('tag:' ):].rstrip ('\n ' )
154+ continue
107155 index = line .strip ().find ('commit:' )
108156 if index >= 0 :
109157 commit = line [index + len ('commit:' ):].rstrip ('\n ' )
@@ -113,14 +161,19 @@ def at_parse_idf_version(idf_ver_file, pairs):
113161 repo = line [index + len ('repository:' ):].rstrip ('\n ' )
114162 continue
115163
116- if len (branch ) <= 0 :
117- sys .exit ('ERROR: idf branch is not defined' )
164+ if branch and tag :
165+ sys .exit ('ERROR: idf branch and tag cannot both be defined' )
166+ if not branch and not tag :
167+ sys .exit ('ERROR: idf branch or tag must be defined' )
118168 if len (commit ) <= 0 :
119169 sys .exit ('ERROR: idf commit is not defined' )
120170 if len (repo ) <= 0 :
121171 sys .exit ('ERROR: idf url is not defined' )
122172
123- pairs .append (('esp-idf' , repo , branch , commit , 1 ))
173+ if branch :
174+ pairs .append (('esp-idf' , repo , branch , 'branch' , commit , 1 ))
175+ else :
176+ pairs .append (('esp-idf' , repo , tag , 'tag' , commit , 1 ))
124177
125178def at_parse_submodules (submodules_file , pairs ):
126179 import configparser
@@ -130,7 +183,7 @@ def at_parse_submodules(submodules_file, pairs):
130183 config .read (submodules_file )
131184 for item in config .sections ():
132185 at_macro_pairs .append ('AT_' + item .split ()[1 ].strip ('"' ).upper () + '_SUPPORT' )
133- pairs .append ((config [item ]['path' ], config [item ]['url' ], config [item ]['branch' ], config [item ]['commit' ], 0 ))
186+ pairs .append ((config [item ]['path' ], config [item ]['url' ], config [item ]['branch' ], 'branch' , config [item ]['commit' ], 0 ))
134187
135188def at_submodules_update (platform , module ):
136189 config_dir = os .path .join (os .getcwd (), 'module_config' , 'module_{}' .format (module .lower ()))
@@ -155,8 +208,8 @@ def at_submodules_update(platform, module):
155208 ESP_LOGE ('Failed to parse submodules:"{}" ({})' .format (submodules_file , e ))
156209 sys .exit (2 )
157210
158- for path , repo , branch , commit , redirect in list (filter (None , pairs )):
159- at_sync_submodule (path , repo , branch , commit , redirect )
211+ for path , repo , ref , ref_type , commit , redirect in list (filter (None , pairs )):
212+ at_sync_submodule (path , repo , ref , ref_type , commit , redirect )
160213
161214 ESP_LOGI ('submodules check completed for updates.' )
162215
0 commit comments