2023-10-11 14:55:18 +02:00
import sys
import os
import tomllib
import subprocess
import platform
# Global Params
param1 = " "
param2 = " "
2023-10-11 17:42:27 +02:00
fx_mode = False
project_list = [ ]
parameter_validation_check = False
project = [ ]
2023-10-11 14:55:18 +02:00
# Functions
def get_args ( ) :
global param1
global param2
global fx_mode
2023-10-11 17:42:27 +02:00
if len ( sys . argv ) == 1 :
2023-10-11 14:55:18 +02:00
help ( )
2023-10-11 17:42:27 +02:00
if len ( sys . argv ) > 1 :
2023-10-11 14:55:18 +02:00
param1 = sys . argv [ 1 ]
2023-10-11 17:42:27 +02:00
if len ( sys . argv ) > 2 :
2023-10-11 14:55:18 +02:00
param2 = sys . argv [ 2 ]
2023-10-11 17:42:27 +02:00
fx_mode = True
2023-10-11 14:55:18 +02:00
def help ( ) :
print ( " Usage build and upload Project: " )
print ( " run.py list Get a list of all Projects " )
print ( " run.py new <Project-Name> Create a new game in the Project folder " )
print ( " run.py <Project-Name> For uploading a game " )
print ( " " )
print ( " Usage FX-Data build and upload: " )
print ( " run.py fxbuild <Project-Name> Build your fxdata " )
print ( " run.py fxupload <Project-Name> Upload your fxdata " )
print ( " run.py fxall <Project-Name> Build and Upload your fxdata " )
print ( " and the game in one step " )
sys . exit ( )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def get_projects ( ) :
global project_list
with open ( " Cargo.toml " , " rb " ) as f :
data = tomllib . load ( f )
2023-10-11 17:42:27 +02:00
path = data [ " workspace " ] [ " members " ]
2023-10-11 14:55:18 +02:00
for p in path :
name = p . split ( " / " ) [ - 1 ]
2023-10-11 17:42:27 +02:00
if name == " arduboy-rust " :
2023-10-11 14:55:18 +02:00
continue
2023-10-11 17:42:27 +02:00
project = [ name , p ]
2023-10-11 14:55:18 +02:00
project_list . append ( project )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def validate_args ( ) :
global parameter_validation_check
global project
if fx_mode :
for p in project_list :
2023-10-11 17:42:27 +02:00
if param2 in p :
parameter_validation_check = True
2023-10-11 14:55:18 +02:00
project = p
else :
for p in project_list :
2023-10-11 17:42:27 +02:00
if param1 in p :
parameter_validation_check = True
2023-10-11 14:55:18 +02:00
project = p
if not parameter_validation_check :
help ( )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def execute_options ( ) :
2023-10-11 17:42:27 +02:00
if param1 == " list " :
group = " "
2023-10-11 14:55:18 +02:00
for p in project_list :
2023-10-11 17:42:27 +02:00
if not group == p [ 1 ] . split ( " / " ) [ - 2 ] :
group = p [ 1 ] . split ( " / " ) [ - 2 ]
2023-10-11 14:55:18 +02:00
print ( f " \n { group } : " )
print ( f " { p [ 0 ] } " )
print ( " " )
2023-10-12 09:54:42 +02:00
sys . exit ( 0 )
2023-10-11 17:42:27 +02:00
if param1 == " new " :
2023-10-11 14:55:18 +02:00
create_new_project ( )
2023-10-12 09:54:42 +02:00
sys . exit ( 0 )
2023-10-11 17:42:27 +02:00
if param1 == " doc " :
if platform . system ( ) == " Linux " :
cmd = " cargo doc -p arduboy-rust; rm -r ./docs/doc/; cp -r ./target/arduboy/doc ./docs/ "
process = subprocess . Popen ( cmd , stdout = subprocess . PIPE )
elif platform . system ( ) == " Windows " :
cmd = ' cargo doc -p arduboy-rust; rm -r ./docs/doc/; cp -r ./target/arduboy/doc ./docs/ '
process = subprocess . Popen ( [ " powershell " , " -Command " , cmd ] , stdout = subprocess . PIPE )
else :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 17:42:27 +02:00
for c in iter ( lambda : process . stdout . read ( 1 ) , b " " ) :
sys . stdout . buffer . write ( c )
if process . returncode != 0 :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def _dumps_value ( value ) :
if isinstance ( value , bool ) :
return " true " if value else " false "
elif isinstance ( value , ( int , float ) ) :
return str ( value )
elif isinstance ( value , str ) :
return f ' " { value } " '
elif isinstance ( value , list ) :
return f " [ { ' , ' . join ( _dumps_value ( v ) for v in value ) } ] "
else :
raise TypeError ( f " { type ( value ) . __name__ } { value !r} is not supported " )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def dumps ( toml_dict , table = " " ) :
toml = [ ]
for key , value in toml_dict . items ( ) :
if isinstance ( value , dict ) :
table_key = f " { table } . { key } " if table else key
toml . append ( f " \n [ { table_key } ] \n { dumps ( value , table_key ) } " )
else :
toml . append ( f " { key } = { _dumps_value ( value ) } " )
return " \n " . join ( toml )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def create_new_project ( ) :
2023-10-11 17:42:27 +02:00
project_name = param2 . replace ( " - " , " _ " )
2023-10-11 14:55:18 +02:00
for p in project_list :
2023-10-11 17:42:27 +02:00
if p [ 0 ] == project_name :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 17:42:27 +02:00
error_code = os . system ( f ' cargo new --vcs=none --lib ./Project/ { project_name } ' )
if error_code > 0 :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 14:55:18 +02:00
# Edit main Cargo.toml
with open ( " Cargo.toml " , " rb " ) as f :
data = tomllib . load ( f )
data [ " workspace " ] [ " members " ] . append ( f " Project/ { project_name } " )
2023-10-11 17:42:27 +02:00
with open ( " Cargo.toml " , " w " ) as f :
2023-10-11 14:55:18 +02:00
f . write ( dumps ( data ) )
# Edit new project Cargo.toml
with open ( f " Project/ { project_name } /Cargo.toml " , " rb " ) as f :
data = tomllib . load ( f )
2023-10-11 17:42:27 +02:00
newdata = { }
newdata [ " package " ] = data [ " package " ]
newdata [ " lib " ] = { ' crate-type ' : [ " staticlib " ] }
newdata [ " dependencies " ] = { " arduboy-rust " : { " path " : " ../../arduboy-rust " } }
with open ( f " Project/ { project_name } /Cargo.toml " , " w " ) as f :
2023-10-11 14:55:18 +02:00
f . write ( dumps ( newdata ) )
# Edit lib.rs
2023-10-11 17:42:27 +02:00
with open ( f " Project/ { project_name } /src/lib.rs " , " w " ) as f :
2023-10-11 14:55:18 +02:00
f . write ( ''' #![no_std]
#![allow(non_upper_case_globals)]
/ / Include the Arduboy Library
#[allow(unused_imports)]
use arduboy_rust : : prelude : : * ;
#[allow(dead_code)]
const arduboy : Arduboy2 = Arduboy2 : : new ( ) ;
/ / Progmem data
/ / dynamic ram variables
/ / The setup ( ) function runs once when you turn your Arduboy on
#[no_mangle]
pub unsafe extern " C " fn setup ( ) {
/ / put your setup code here , to run once :
}
/ / The loop ( ) function repeats forever after setup ( ) is done
#[no_mangle]
#[export_name = "loop"]
pub unsafe extern " C " fn loop_ ( ) {
/ / put your main code here , to run repeatedly :
} ''' )
2023-10-11 18:05:53 +02:00
with open ( f " Project/ { project_name } /config.toml " , " w " ) as f :
data = ''' Libraries = [
" Arduboy2 " ,
#"ArduboyTones",
#"ArduboyFX",
#"ArdVoice",
#"Serial",
" EEPROM " ,
" Arduino " ,
] '''
f . writelines ( data )
2023-10-11 14:55:18 +02:00
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def generate_import_h ( ) :
with open ( f " { project [ 1 ] } /config.toml " , " rb " ) as f :
data = tomllib . load ( f )
2023-10-11 17:42:27 +02:00
strings = [ " #pragma once \n " ]
2023-10-11 14:55:18 +02:00
for lib in data [ " Libraries " ] :
strings . append ( f " #define { lib } _Library ; \n " )
f = open ( " arduboy-rust/Wrapper-Project/src/imports.h " , " w " )
f . writelines ( strings )
f . close ( )
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def upload_to_arduboy ( ) :
if not fx_mode :
2023-10-11 17:42:27 +02:00
game_name = param1
2023-10-11 14:55:18 +02:00
else :
2023-10-11 17:42:27 +02:00
game_name = param2
if platform . system ( ) == " Linux " :
cmd = f " cargo build -p { game_name } --release; cp ./target/arduboy/release/lib { game_name } .a ./arduboy-rust/Wrapper-Project/lib/libgame.a; cd arduboy-rust/Wrapper-Project/; pio run -v -t upload; cp ./.pio/build/arduboy/firmware.hex ./build/ { game_name } .hex; pio run -t clean; rm ./lib/libgame.a; cd ../../ "
2023-10-11 14:55:18 +02:00
process = subprocess . Popen ( cmd , stdout = subprocess . PIPE )
2023-10-11 17:42:27 +02:00
elif platform . system ( ) == " Windows " :
cmd = f ' cargo build -p { game_name } --release; cp ./target/arduboy/release/lib { game_name } .a ./arduboy-rust/Wrapper-Project/lib/libgame.a; cd arduboy-rust/Wrapper-Project/; pio run -v -t upload; cp ./.pio/build/arduboy/firmware.hex ./build/ { game_name } .hex; pio run -t clean; rm lib/libgame.a; cd ../../ '
2023-10-11 14:55:18 +02:00
process = subprocess . Popen ( [ " powershell " , " -Command " , cmd ] , stdout = subprocess . PIPE )
else :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 17:42:27 +02:00
for c in iter ( lambda : process . stdout . read ( 1 ) , b " " ) :
2023-10-11 14:55:18 +02:00
sys . stdout . buffer . write ( c )
if process . returncode != 0 :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 14:55:18 +02:00
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def fx_build ( ) :
2023-10-11 17:42:27 +02:00
error_code = os . system ( f ' python ./Tools/Arduboy-Python-Utilities/fxdata-build.py ./ { project [ 1 ] } /fxdata/fxdata.txt ' )
if error_code > 0 :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 14:55:18 +02:00
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def fx_upload ( ) :
2023-10-11 17:42:27 +02:00
error_code = os . system ( f ' python ./Tools/Arduboy-Python-Utilities/fxdata-upload.py ./ { project [ 1 ] } /fxdata/fxdata.bin ' )
if error_code > 0 :
2023-10-12 09:54:42 +02:00
sys . exit ( 1 )
2023-10-11 14:55:18 +02:00
2023-10-11 17:42:27 +02:00
2023-10-11 14:55:18 +02:00
def fx_commands ( ) :
print ( " " )
2023-10-11 17:42:27 +02:00
if param1 == " fxbuild " :
2023-10-11 14:55:18 +02:00
fx_build ( )
2023-10-11 17:42:27 +02:00
elif param1 == " fxupload " :
2023-10-11 14:55:18 +02:00
fx_upload ( )
2023-10-11 17:42:27 +02:00
elif param1 == " fxall " :
2023-10-11 14:55:18 +02:00
fx_build ( )
fx_upload ( )
upload_to_arduboy ( )
# Execute Script
get_args ( )
get_projects ( )
execute_options ( )
validate_args ( )
generate_import_h ( )
if fx_mode :
fx_commands ( )
else :
upload_to_arduboy ( )