@@ -157,13 +157,47 @@ def download_and_extract(source, destination):
157157 output .warning (f"Downloaded { destination_file } but did not extract (unsupported type)" )
158158
159159
160+ def _has_valid_commands (directory ):
161+ """
162+ Check the first-level subdirectories of the given directory to find files
163+ that appear to contain valid tome commands.
164+ """
165+ # List only the first-level subdirectories of 'directory'
166+ for subdir_name in os .listdir (directory ):
167+ subdir = os .path .join (directory , subdir_name )
168+ if os .path .isdir (subdir ):
169+ # Iterate over the files in the first-level subdirectory
170+ for file in os .listdir (subdir ):
171+ file_path = os .path .join (subdir , file )
172+ if os .path .isfile (file_path ):
173+ ext = os .path .splitext (file )[1 ]
174+ # Check if the filename starts with "tome_" and has a recognized shell extension
175+ if file .startswith ("tome_" ) and ext in ['.sh' , '.bat' , '.ps1' , '.bash' , '.zsh' ]:
176+ return True
177+ # Alternatively, if it is a Python file, search for the decorator usage
178+ if ext == ".py" :
179+ try :
180+ with open (file_path , 'r' , encoding = 'utf-8' ) as f :
181+ content = f .read ()
182+ if "@tome_command(" in content :
183+ return True
184+ except Exception :
185+ # Ignore files that cannot be read
186+ continue
187+ return False
188+
189+
160190def install_from_source (source , cache_destination_folder , force_requirements , create_env ):
161191 if os .path .exists (cache_destination_folder ):
162192 rmdir (cache_destination_folder )
163193 if source .type is SourceType .GIT :
164194 commit = clone_git_repo (source , cache_destination_folder )
165195 source .commit = commit
196+ if not _has_valid_commands (cache_destination_folder ):
197+ raise TomeException ("No valid tome commands were found in the cloned repository." )
166198 elif source .type is SourceType .FOLDER :
199+ if not _has_valid_commands (source .uri ):
200+ raise TomeException (f"No valid tome commands were found in the '{ source .uri } ' folder." )
167201 process_folder (source .uri , cache_destination_folder )
168202 elif source .type is SourceType .FILE :
169203 assert is_compressed_file (source .uri )
@@ -188,14 +222,16 @@ def install_editable(source, cache_base_folder, force_requirements, create_env):
188222 Updates the cache directory with a new source installed in editable mode.
189223 If an editable installations file doesn't exist, it creates a new one.
190224
191- :param create_env:
192- :param force_requirements:
225+ :param create_env: Whether to create a virtual environment for the source.
226+ :param force_requirements: Force installation of requirements.
193227 :param source: The source of the scripts to be installed in editable mode.
194228 :param cache_base_folder: The cache directory where the installations file is stored.
195229 """
196230 output = TomeOutput ()
197231 os .makedirs (cache_base_folder , exist_ok = True )
198232
233+ if not _has_valid_commands (source .uri ):
234+ raise TomeException (f"No valid tome commands were found in the '{ source .uri } ' folder." )
199235 _install_requirements (source .uri , force_requirements , create_env )
200236
201237 editables_file = TomePaths (cache_base_folder ).editables_path
0 commit comments