import sys, os, subprocess, shutil, json, requests, zipfile, io
from packaging import version
from pathlib import Path
from getpass import getpass
######### Parameter Definitions ###################################################################
cwd = Path.cwd()
folder_name = 'kostergroup-SIMsalabim-'
min_fpc_version = '3.2.0'
######### Function Definitions ####################################################################
[docs]
def cmd_yes_no_question(question, default = "yes"):
"""_summary_
Parameters
----------
question : str
question to ask the user
default : str, optional
default answer, by default "yes"
Returns
-------
bool
whether the default answer is valid or not
Raises
------
ValueError
If the default answer is not valid
"""
# valid answers (yes/no)
valid = {'yes' : True, 'y': True, 'ye': True, 'no': False, 'n': False}
# Set the default answer.
if default is None:
prompt = " [y/n] "
elif default == 'yes':
prompt = " [Y/n] "
elif default == 'no':
prompt = " [y/N] "
else:
raise ValueError(f"Invalid default answer: {default}\n")
while True:
# Capture user input
sys.stdout.write(question + prompt)
choice = input()
# convert the input to lowercase
choice = choice.lower()
if default is not None and choice == "":
# Use default value
return valid[default]
elif choice in valid:
# Use user input
return valid[choice]
else:
# Incorrect input
sys.stdout.write('Please respond with "y" or "n"\n')
[docs]
def clear_current_working_directory(cwd, folder_name='kostergroup-SIMsalabim-'):
"""_summary_
Parameters
----------
cwd : string
Current working directory
folder_name : string, optional
Name of the folder to download, by default 'kostergroup-SIMsalabim-'
Returns
-------
bool
Whether the folder was removed or not
"""
# Clear the current working directory
for dirpath, dirnames, files in os.walk(cwd):
for dirname in dirnames:
if dirname.startswith(folder_name):
result = cmd_yes_no_question(f"Are you sure you want to overwrite the {dirname} folder?")
if result == True:
shutil.rmtree(os.path.join(cwd,dirname))
print(f"Found and removed a folder named {dirname}")
return True
elif result is False:
print(f"Not allowed to write into folder {dirname}")
return False
else:
# print(f"No folder found named SIMsalabim, continue.")
return True
[docs]
def get_SIMsalabim_source(cwd, folder_name='kostergroup-SIMsalabim-',verbose=False):
""" Get the latest release from the Kostergroup Github
Parameters
----------
cwd : string
Current working directory
folder_name : string, optional
Name of the folder to download, by default 'kostergroup-SIMsalabim-'
verbose : bool, optional
Print verbose output, by default False
Returns
-------
int
0 : Success
2 : Failed
3 : Failed
"""
if verbose:
print("Getting the latest release from the Kostergroup Github")
# Get the SIMsalabim source code.
if os.path.exists(os.path.join(cwd, 'SIMsalabim')):
# Pop out dialog box to confirm overwriting
result = cmd_yes_no_question("Are you sure you want to overwrite the 'SIMsalabim' folder?")
if result == True:
# Remove folder
shutil.rmtree(os.path.join(cwd, 'SIMsalabim'))
# # Get the files from the latest release
url = 'https://api.github.com/repos/kostergroup/SIMsalabim/zipball'
response = requests.get(url)
# Open the zip file
z = zipfile.ZipFile(io.BytesIO(response.content))
# Extract all the files
z.extractall(path=cwd)
for dirpath, dirnames, files in os.walk(cwd):
for dirname in dirnames:
if dirname.startswith(folder_name):
# Rename folder
shutil.move(os.path.join(cwd, dirname), os.path.join(cwd, 'SIMsalabim'))
print("\nGot the latest release of SIMsalabim")
return 0
else:
print('We keep the current SIMsalabim version')
return 0
else:
# # Get the files from the latest release
url = 'https://api.github.com/repos/kostergroup/SIMsalabim/zipball'
response = requests.get(url)
# Open the zip file
z = zipfile.ZipFile(io.BytesIO(response.content))
# Extract all the files
z.extractall(path=cwd)
for dirpath, dirnames, files in os.walk(cwd):
for dirname in dirnames:
if dirname.startswith(folder_name):
# print(f"Found a folder named {dirname}")
# Rename folder
shutil.move(os.path.join(cwd, dirname), os.path.join(cwd, 'SIMsalabim'))
print("\nGot the latest release of SIMsalabim")
return 0
[docs]
def get_SIMsalabim_assets(cwd,folder_name='kostergroup-SIMsalabim-',verbose=False):
""" Get the latest compiled binaries from the Kostergroup Github
Parameters
----------
cwd : string
Current working directory
folder_name : string, optional
Name of the folder to download, by default 'kostergroup-SIMsalabim-'
verbose : bool, optional
Print verbose output, by default False
Returns
-------
int
0 : Success
1 : Success
2 : Failed
3 : Failed
"""
if verbose:
print("Getting the latest compiled binaries from the Kostergroup Github")
# Get the assets from the latest release
url = "https://api.github.com/repos/kostergroup/SIMsalabim/releases/latest"
response = requests.get(url)
data = json.loads(response.text)
for asset in data["assets"]:
download_url = asset["browser_download_url"]
filename = asset["name"]
response = requests.get(download_url)
open(os.path.join(cwd,filename), "wb").write(response.content)
for dirpath, dirnames, files in os.walk(cwd):
for filename in files:
if filename.startswith('simss') and os.path.exists(os.path.join(cwd, filename)):
print(f"Found a folder named {filename}")
# Rename folder
shutil.move(os.path.join(cwd, filename), os.path.join(cwd, 'SIMsalabim','SimSS',filename))
elif filename.startswith('zimt') and os.path.exists(os.path.join(cwd, filename)):
print(f"Found a folder named {filename}")
# Rename folder
shutil.move(os.path.join(cwd, filename), os.path.join(cwd, 'SIMsalabim','ZimT',filename))
else:
pass
return 1
[docs]
def use_SIMsalabim_source(cwd, folder_name='kostergroup-SIMsalabim-'):
""" Use the SIMsalabim source code
Parameters
----------
cwd : string
Current working directory
folder_name : string, optional
Name of the folder to download, by default 'kostergroup-SIMsalabim-'
Returns
-------
int
0 : Success
2 : Failed
3 : Failed
"""
# Clear the working directory. TEMP disabled
# result = clear_current_working_directory(cwd, folder_name)
result = True
if result == True:
result_get = get_SIMsalabim_source(cwd, folder_name)
return result_get
elif result == False:
print('Script terminated manually')
return 3
else:
print('Failed')
return 2
[docs]
def install_SIMsalabim(cwd, folder_name='kostergroup-SIMsalabim-',verbose=False):
"""Install SIMsalabim in the current working directory
Parameters
----------
cwd : string
Current working directory
folder_name : string, optional
Name of the folder to download, by default 'kostergroup-SIMsalabim-'
verbose : bool, optional
Print verbose output, by default False
Returns
-------
int
0 : Success
1 : Success
2 : Failed
3 : Failed
"""
# Check if fpc installed
if verbose:
print("Checking for Free Pascal Compiler (fpc) package")
if shutil.which("fpc") is not None:
# fpc is installed, check the version and print to stdout.
result = subprocess.run(["fpc", "-iV"], stdout=subprocess.PIPE, text=True)
fpc_version = result.stdout
# remove possible newline character
if '\n' in fpc_version:
fpc_version = fpc_version.strip('\n')
# fpc version must be larger than min_fpc_version
if version.parse(fpc_version) > version.parse(min_fpc_version):
if verbose:
print(f'Free Pascal Compiler (fpc) is installed with version >= {min_fpc_version}\n')
result_fpc = use_SIMsalabim_source(cwd, folder_name)
# sys.exit(result_fpc)
# Compile the programs
# compile simss with fpc in os.path.join(path2prog,'SimSS')
os.chdir(os.path.join(cwd,'SIMsalabim','SimSS'))
os.system('fpc simss.pas')
os.chdir(cwd)
# compile zimt with fpc in os.path.join(path2prog,'ZimT')
cwd = os.getcwd() # Get current working directory
os.chdir(os.path.join(cwd,'SIMsalabim','ZimT'))
os.system('fpc zimt.pas')
os.chdir(cwd)
if verbose:
print('SIMsalabim programs have been compiled successfully!')
else:
# fpc version requirement not met
print(f'Installed Free Pascal Compiler (fpc) version is {fpc_version}, but must be at least 3.2.0\n')
result = cmd_yes_no_question("Do you want to continue with the pre-compiled binaries (y) or abort and update the Free Pascal Compiler (n) (recommended)", 'no')
if result is True:
# download assets
print("\ndownload assets")
result_assets = get_SIMsalabim_assets(cwd, verbose)
sys.exit(result_assets)
elif result is False:
# return and exit
sys.exit(3)
else:
# fpc is not installed.
print("Free Pascal Compiler is not installed.\n")
result = cmd_yes_no_question("Do you want to continue with the pre-compiled binaries (y) or abort and install the Free Pascal Compiler (n) (recommended)", 'no')
if result is True:
# download assets
print("\ndownload assets")
result_assets = get_SIMsalabim_assets(cwd, verbose)
sys.exit(result_assets)
elif result is False:
# return and exit
sys.exit(3)
[docs]
def install_fpc_Linux():
""" Install Free Pascal Compiler on Linux
"""
# check if system is Linux
if os.name != 'posix':
print('This function is only available on Linux systems')
sys.exit()
# check if apt-get is available
if shutil.which("apt-get") is None:
print('apt-get is not available on this system')
sys.exit()
# Install Free Pascal Compiler
password = getpass('Sudo password:')
# run the command sudo apt-get install fp-compiler and enter the password and print the output
os.system('echo {} | sudo -S apt-get install fp-compiler'.format(password))
# def install_parallel_Linux():
# """ Install GNU Parallel on Linux
# """
# # check if system is Linux
# if os.name != 'posix':
# print('This function is only available on Linux systems')
# sys.exit()
# # check if apt-get is available
# if shutil.which("apt-get") is None:
# print('apt-get is not available on this system')
# sys.exit()
# # Install GNU Parallel
# password = getpass('Sudo password:')
# # run the command sudo apt-get install parallel and enter the password and print the output
# os.system('echo {} | sudo -S apt-get install parallel'.format(password))
# def fpc_prog(cwd,prog_name):
# """_summary_
# Parameters
# ----------
# cwd : string
# Current working directory
# prog_name : string
# Name of the program to compile
# """
# # Check if fpc installed
# if verbose:
# print("Checking for Free Pascal Compiler (fpc) package")
# if shutil.which("fpc") is not None:
# # fpc is installed, check the version and print to stdout.
# result = subprocess.run(["fpc", "-iV"], stdout=subprocess.PIPE, text=True)
# fpc_version = result.stdout
# # remove possible newline character
# if '\n' in fpc_version:
# fpc_version = fpc_version.strip('\n')
# # fpc version must be larger than min_fpc_version
# if version.parse(fpc_version) > version.parse(min_fpc_version):
# if verbose:
# print(f'Free Pascal Compiler (fpc) is installed with version >= {min_fpc_version}\n')
# # Compile the programs
# os.chdir(os.path.join(cwd,prog_name))
# os.system(f'fpc {prog_name}.pas')
# os.chdir(cwd)
# else:
# # fpc version requirement not met
# print(f'Installed Free Pascal Compiler (fpc) version is {fpc_version}, but must be at least 3.2.0\n')
# result = cmd_yes_no_question("Do you want to continue with the pre-compiled binaries (y) or abort and update the Free Pascal Compiler (n) (recommended)", 'no')
# if result is True:
# # download assets
# print("\ndownload assets")
# result_assets = get_SIMsalabim_assets(cwd, verbose)
# sys.exit(result_assets)
# elif result is False:
# # return and exit
# sys.exit(3)
# else:
# # fpc is not installed.
# print("Free Pascal Compiler is not installed.\n")
# sys.exit(3)
[docs]
def fpc_prog(cwd,prog_name,show_term_output=True,force_fpc=True,verbose=True):
"""Compile program using fpc
Parameters
----------
cwd : string
String of the absolute path to the program
prog_name : string
Name of the program to compile
show_term_output : bool, optional
show terminal output from the compilation, by default True
force_fpc : bool, optional
force recompile with fpc even if compiled program already exists, by default True
verbose : bool, optional
print output of the compilation, by default True
"""
is_windows = (os.name == 'nt') # Check if we are on Windows
cwd = str(cwd) # Convert to string
# check if
compiled = False
while not compiled:
if shutil.which("fpc") is not None:
# fpc is installed, check the version and print to stdout.
result = subprocess.run(["fpc", "-iV"], stdout=subprocess.PIPE, text=True)
fpc_version = result.stdout
# remove possible newline character
if '\n' in fpc_version:
fpc_version = fpc_version.strip('\n')
# fpc version must be larger than min_fpc_version
if version.parse(fpc_version) >= version.parse(min_fpc_version):
if verbose:
print(f'Free Pascal Compiler (fpc) is installed with version >= {min_fpc_version}\n')
# Check if the program is already compiled
if (os.path.isfile(os.path.join(cwd,prog_name+'.exe')) and is_windows) or (os.path.isfile(os.path.join(cwd,prog_name)) and not is_windows):
if force_fpc:
if show_term_output == True:
output_direct = None
else:
output_direct = subprocess.DEVNULL
try:
subprocess.check_call(['fpc', prog_name.lower()+'.pas'], encoding='utf8', stdout=output_direct, cwd=cwd, shell=is_windows)
except subprocess.CalledProcessError:
print('Error compiling '+prog_name+' in '+cwd)
raise ChildProcessError
if verbose:
print('\n'+prog_name+' already existed but was recompiled'+'\n')
else:
if verbose:
print('\n'+prog_name+' already compiled')
else: # Compile the program
if show_term_output == True:
output_direct = None
else:
output_direct = subprocess.DEVNULL
try:
subprocess.check_call(['fpc', prog_name.lower()+'.pas'], encoding='utf8', stdout=output_direct, cwd=cwd, shell=is_windows)
if verbose:
print('\n'+prog_name+' was not compiled so we did it!'+'\n')
except subprocess.CalledProcessError:
print('Error compiling '+prog_name+' in '+cwd)
raise ChildProcessError
compiled = True
else:
# fpc version requirement not met
print(f'Installed Free Pascal Compiler (fpc) version is {fpc_version}, but must be at least 3.2.0\n')
print('Please update the Free Pascal Compiler to the latest version')
sys.exit(3)
else:
# fpc is not installed.
print("Free Pascal Compiler is not installed.\n")
result = cmd_yes_no_question("Do you want to continue and install the Free Pascal Compiler (only works on Linux) (y) or abort (n) (recommended)", 'no')
if result is True:
# install fpc
install_fpc_Linux()
# sys.exit(0)
elif result is False:
# return and exit
sys.exit(3)
######### Script ##################################################################################
if __name__ == "__main__":
install_SIMsalabim(cwd,verbose=True)
sys.exit(0)