@@ -35,7 +35,11 @@ def __init__(self):
3535 # Load variables from .env file into os.environ.
3636 env_path = Path (".env" )
3737 if not env_path .exists ():
38- return
38+ print (f"Error: .env file not found at { env_path .absolute ()} " )
39+ print (
40+ "This file is required for build configuration (the GODOT_VERSION, TEMPLATES_REPO env vars are required)"
41+ )
42+ sys .exit (1 )
3943
4044 for line in env_path .read_text ().splitlines ():
4145 line = line .strip ()
@@ -108,6 +112,34 @@ def run_command(command, check=True, capture_output=False):
108112 return result .stdout .strip () if capture_output else None
109113
110114
115+ def download_butler (target_dir = None ):
116+ """
117+ Download Butler CLI tool for itch.io uploads.
118+
119+ Args:
120+ target_dir: Directory to install Butler to. If None, installs to current directory.
121+ For local development, typically ~/.local/bin is used.
122+ """
123+ print ("Downloading Butler..." )
124+ butler_dir = Path (target_dir ) if target_dir else Path ("." )
125+ butler_dir .mkdir (parents = True , exist_ok = True )
126+ zip_path = butler_dir / "butler.zip"
127+
128+ BUTLER_DOWNLOAD_URL = (
129+ "https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default"
130+ )
131+ urllib .request .urlretrieve (BUTLER_DOWNLOAD_URL , zip_path )
132+ with zipfile .ZipFile (zip_path , "r" ) as archive :
133+ archive .extractall (butler_dir )
134+ butler_path = (butler_dir / "butler" ).resolve ()
135+ os .chmod (butler_path , 0o755 )
136+ zip_path .unlink ()
137+ run_command (f'"{ butler_path } " -V' )
138+ print ("✓ Downloaded Butler\n " )
139+
140+ return butler_dir
141+
142+
111143def download_godot_and_templates ():
112144 """Download Godot headless build and export templates from GitHub."""
113145 if not build_info .godot_version :
@@ -159,11 +191,12 @@ def prepare_course_scripts():
159191def prepare_ci ():
160192 """
161193 Set up the CI environment: download Godot headless build and export templates,
162- install required software, and prepare course scripts.
194+ install required software, download Butler, and prepare course scripts.
163195 """
164196 print ("Preparing CI environment...\n " )
165197
166198 download_godot_and_templates ()
199+ # download_butler()
167200
168201 # Rename Godot binary to a standard name and make it executable
169202 source_file = "godot_server.x11.opt.tools.64"
@@ -290,24 +323,12 @@ def push_platform(platform):
290323 print (f"Error: Missing itch.io credentials: { ', ' .join (missing )} " )
291324 sys .exit (1 )
292325
293- # Install butler if needed
294326 if not shutil .which ("butler" ):
295- print ("Butler not found, downloading..." )
296- butler_dir = Path .home () / ".local" / "bin"
297- butler_dir .mkdir (parents = True , exist_ok = True )
298- zip_path = butler_dir / "butler.zip"
299-
300- BUTLER_DOWNLOAD_URL = (
301- "https://broth.itch.zone/butler/linux-amd64/LATEST/archive/default"
302- )
303- urllib .request .urlretrieve (BUTLER_DOWNLOAD_URL , zip_path )
304- with zipfile .ZipFile (zip_path , "r" ) as archive :
305- archive .extractall (butler_dir )
306- os .chmod (butler_dir / "butler" , 0o755 )
307- zip_path .unlink ()
327+ print ("Butler not found in PATH, downloading for local use..." )
328+ butler_dir = download_butler (Path .home () / ".local" / "bin" )
308329 os .environ ["PATH" ] = f"{ butler_dir } :{ os .environ ['PATH' ]} "
330+ else :
309331 run_command ("butler -V" )
310- print ("✓ Butler installed\n " )
311332
312333 build_dir = build_info .get_output_directory (platform )
313334 if not Path (build_dir ).exists ():
0 commit comments