Files
SwissFEL-HL/HeiligeListe.py

352 lines
15 KiB
Python

# This is the main program to generate the 'Heilige Liste'
import os
import glob
import sys
import shutil
import json
import datetime
import argparse
sys.path.insert(0,os.path.join(os.path.dirname(__file__), 'Python_Code'))
import ProtoListe
import WriteExcel
import AssemblyList
from CompareList import compareLists
class HeiligeListe:
def __init__(self):
self.lattice = 'None'
self.workdir = ''
self.export = WriteExcel.Export()
self.assembly = AssemblyList.AssemblyList()
self.PLs = [ProtoListe.ProtoListe(i) for i in range(3)]
def HLUpdateLattice(self):
"""
Routine to copy the relevant online model files into the reference directories.
This synchronize the local lattice with the official one. The function is rather administrative
:return: True or False, depending if the files could be found
"""
dirsource = os.path.abspath(
os.path.join(os.path.abspath(os.sep), 'sf', 'bd', 'applications', 'OnlineModel', 'current'))
dirtarget = os.path.join(os.path.dirname(__file__), 'Python_Code')
files = ['OMLayout.py', 'OMFacility.py', 'OMFacilityAccess.py', 'OMAppTemplate.py', 'OMType.py',
'OMEnergyManager.py']
for file in files:
pfile = os.path.join(dirsource, file)
try:
shutil.copy(pfile, dirtarget)
except IOError as e:
print("Unable to copy file. %s" % e)
return False
return True
def HLClone(self, dirname = "Work", phase='All'):
"""
Routine to take all reference input files and to generate a working directory to copy all relevant files
to the working directory so that it can be build. Existing working directory are deleted
:param dirname: name of working directory, where relevant files are copied to.
:param phase: either 'Current', 'Planned', 'Future', or 'All' (default). Tag is case-sensitive
:return: True or False if directory can be generated
"""
if len(dirname) < 1:
return False
phases=['Current','Planned','Final']
if not ( phase == 'All' or phase in phases):
print('Unrecognized phase. Supported are Current, Planned and Final')
return False
# step 1 - generate working directory or clean it up if it exists
folder = os.path.join(os.path.dirname(__file__), dirname)
try:
os.mkdir(folder)
except FileExistsError as e0:
print('Working directory exists. Cleaning up directory')
for filename in os.listdir(folder):
file_path = os.path.join(folder, filename)
try:
if os.path.isfile(file_path) or os.path.islink(file_path):
os.unlink(file_path)
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
except Exception as e:
print('Failed to delete %s. Reason: %s' % (file_path, e))
# step 2 - generate json file with version and phase
verfile = {'Version': self.PLs[0].SF.Version}
for phs in phases:
if phase == phs or phase == 'All':
verfile[phs]=True
else:
verfile[phs]=False
filepath = os.path.join(folder, 'Version.json')
with open(filepath, 'w') as out:
json.dump(verfile, out)
# step 3 - copy files to working directory
source = os.path.join(os.path.dirname(__file__), 'Sub_assemblies_Lists', 'HL-Components')
try:
shutil.copytree(source, os.path.join(folder, 'HL-Components'))
except IOError as e:
print("Unable to copy folder. %s" % e)
return False
for phase in phases:
if verfile[phase]:
source = os.path.join(os.path.dirname(__file__), 'Sub_assemblies_Lists','Phase %s' % phase)
try:
shutil.copytree(source, os.path.join(folder,'Phase %s' % phase))
except IOError as e:
print("Unable to copy folder. %s" % e)
return False
return True
def HLRelease(self, dirname='Work', phase='All'):
"""
Copies excel files and sub_assembly files into the current directory, add them to git and push it to the git repository
:param dirname: name of working directory
:param phase: either 'Current', 'Planned', 'Future', or 'All'. Tag is case-sensitive
:return:
"""
if len(dirname) < 1:
return False
# initiate git link
from git.repo import Repo
git = Repo.init(os.path.dirname(__file__))
# step 1 - check if working folder exists. Otherwise try to creat it
folder = os.path.join(os.path.dirname(__file__), dirname)
if not os.path.exists(folder):
print('Source Directory does not exist')
return False
# step 2 - read version file
version = {'Version': None, 'Current': False, 'Planned': False, 'Final': False}
with open(os.path.join(folder, 'Version.json'), 'r') as fin:
version = json.load(fin)
if version['Version'] is None:
print('Cannot find version file in working directory')
return False
phs = ['Current', 'Planned', 'Final']
output = []
for ph in phs:
if version[ph] and (phase == 'All' or phase == ph):
output.append(ph)
print(output)
# step3 - copy in release folder
now = datetime.datetime.now()
date_time = now.strftime("%Y_%m_%d_%H_%M_%S")
for out in output:
files = os.path.join(folder, 'HolyList-Lat%s-Phase-%s.xlsx' % (version['Version'], out))
filet = os.path.join('Release', 'HolyList-Lat%s-Phase-%s.xlsx' % (version['Version'], out))
print(files)
if os.path.exists(files):
status=self.backupOldRelease(out,git,date_time)
if not status:
return status
shutil.copy(files,filet)
git.index.add([filet])
else:
print('Holy List File',files,'not found in working directory',folder)
# step 4 - update README file
self.updateREADME()
git.index.add(['README.md'])
# step 5 - final commit and push to repository
git.index.commit("Holy List Release on %s" % date_time)
git.remote('origin').push()
return True
def updateREADME(self):
fcur=None
for file in glob.glob("Release" + os.sep+'HolyList-Lat*Current.xlsx'):
fcur=file
fpla=None
for file in glob.glob("Release" + os.sep+'HolyList-Lat*Planned.xlsx'):
fpla=file
ffin= None
for file in glob.glob("Release" + os.sep + 'HolyList-Lat*Final.xlsx'):
ffin = file
with open('README.md','r') as fin:
fout=open('README_TMP.md','w')
pout = True
for line in fin.readlines():
if '### Machine Lattice' in line:
fout.write(line)
if fcur:
fout.write('\n- Current: [%s](%s)\n' % (fcur.split('-')[1][3:],fcur))
else:
fout.write('\n- Current: not released yet\n')
if fpla:
fout.write('\n- Planned: [%s](%s)\n' % (fpla.split('-')[1][3:],fpla))
else:
fout.write('\n- Planned: not released yet\n')
if ffin:
fout.write('\n- Final: [%s](%s)\n' % (ffin.split('-')[1][3:],ffin))
else:
fout.write('\n- Final: not released yet\n')
now=datetime.datetime.now()
fout.write('\n\n_(Released: %s)_ \n\n' % now.strftime("%d/%m/%Y - %H:%M:%S"))
pout=False
elif '### Optical' in line:
fout.write(line)
pout=True
elif pout:
fout.write(line)
fout.close()
shutil.move('README_TMP.md','README.md')
def backupOldRelease(self,phase,git,date_time):
"""
Copy an existing release file into a backup directory
:param phase: Phase tag (e.g. Current') to filter all files
:param git: link to git repository
:return: Bool
"""
for subdir, dirs, files in os.walk('Release'):
if '/' in subdir: # do not iterate over subdirectories
continue
for file in files:
tags=file.split('-')
if tags[0] !='HolyList':
continue
oldphase=tags[3].split('.')[0]
if oldphase == phase:
filesrc = subdir + os.sep + file
filetar = subdir + os.sep + "Old" + os.sep + date_time
if not os.path.exists(filetar):
os.mkdir(filetar)
try:
gfile = shutil.move(filesrc, filetar)
except IOError as e:
print("Unable to copy file. %s" % e)
return False
print('Archiving old release file as:', gfile)
git.index.add([gfile])
git.index.remove([filesrc])
return True
def HLGenerate(self, dirname = 'Work', phase = 'All', filter = None):
"""
Generate an Excel File with the tabs for 3DExperience, Holy List and Proto List within the defined working
directory. If the directory is not found the command HLClone is performed first.
:param dirname: name of working directory
:param phase: either 'Current', 'Planned', 'Future', or 'All'. Tag is case-sensitive
:return: True or False depending if working directory existed and phase is valid
"""
if len(dirname) < 1:
return False
# step 1 - check if working folder exists. Otherwise try to creat it
folder = os.path.join(os.path.dirname(__file__), dirname)
if not os.path.exists(folder):
status = self.HLClone(dirname = dirname, phase = phase)
if not status:
return False
# step 2 - read in lattice version and phase
version = {'Version': None, 'Current': False,'Planned': False, 'Final': False}
with open(os.path.join(folder,'Version.json'), 'r') as fin:
version = json.load(fin)
if version['Version'] is None:
print('Cannot find version file in working directory')
return False
vers=['Current','Planned','Final']
for nphase, ver in enumerate(vers):
if (phase == 'All' or phase == ver) and version[ver]:
vercomp = self.PLs[nphase].SF.Version
if not vercomp == version['Version']:
print('Lattice mismatch of Cloned Lattice and current Online Model')
print('Please clone working directory with current model again')
return False
# step 3 - calculate layout for Proto list
print('\n------------------------------\nGenerating Proto List:\n')
self.PLs[nphase].generateLayout()
#excelfile = os.path.join(folder, 'HolyList-Lat%s-Phase-%s' % (version['Version'], ver))
#self.export.export(excelfile, self.PLs[nphase], None)
#return True
# step 4 - parse assembly and component lists
print('\n------------------------------\nParsing Assembly and Component Lists:\n')
assemblyfile = os.path.join(folder,'Phase %s' % ver)
print('Parsing Assembly Lists in Directory:',assemblyfile)
self.assembly.readFiles(assemblyfile,folder,nphase)
# step 5 - calculate Holy List
print('\n------------------------------\nGenerating Holy List:\n')
DL = self.assembly.generateLayout(self.PLs[nphase])
# step 6 - write out Excel File
excelfile=os.path.join(folder,'HolyList-Lat%s-Phase-%s' % (version['Version'],ver))
print('\n------------------------------\nWriting Excel File: %s\n' % excelfile)
self.export.export(excelfile, self.PLs[nphase], DL, Filter = filter)
return True
def parse(args):
HL = HeiligeListe()
if len(args) < 2:
print('Command Arguments are missing (e.g. init, generate)')
cmd=args[1].upper()
if cmd == 'INIT':
parser = argparse.ArgumentParser(prog='HLInit', description='Initialize a working directory')
parser.add_argument('-d','--dir', default='Work', help='Name of working directory')
parser.add_argument('-p','--phase', default='Current',
help = 'Phase: Current, Planned, Final, or All',
choices=['Current','Planned','Final','All'])
pargs = parser.parse_args(args[2:])
HL.HLClone(dirname=pargs.dir,phase=pargs.phase)
elif cmd == 'UPDATE':
HL.HLUpdateLattice()
elif cmd == 'GENERATE':
parser = argparse.ArgumentParser(prog='HLGenerate', description='Generate the holy list in the working directory')
parser.add_argument('-d', '--dir', default='Work', help='Name of working directory')
parser.add_argument('-p', '--phase', default='Current',
help='Phase: Current, Planned, Final, or All',
choices=['Current', 'Planned', 'Final', 'All'])
pargs = parser.parse_args(args[2:])
HL.HLGenerate(dirname=pargs.dir, phase=pargs.phase)
elif cmd == 'EXTRACT':
parser = argparse.ArgumentParser(prog='HLExtract', description='Extract a subset of the holy list')
parser.add_argument('-d', '--dir', default='Work', help='Name of working directory')
parser.add_argument('-f', '--filter', default='.*', help='Regular Expression Filter')
parser.add_argument('-p', '--phase', default='Current',
help='Phase: Current, Planned, Final, or All',
choices=['Current', 'Planned', 'Final', 'All'])
pargs = parser.parse_args(args[2:])
HL.HLGenerate(dirname=pargs.dir, phase=pargs.phase,filter=pargs.filter)
elif cmd == 'COMPARE':
if len(args) < 4:
print('Needs argument for the two files to be compared')
return
compareLists(args[2:])
elif cmd == 'RELEASE':
parser = argparse.ArgumentParser(prog='HLRelease',
description='Release the holy list as a new version on gitlab')
parser.add_argument('-d', '--dir', default='Work', help='Name of working directory')
parser.add_argument('-p', '--phase', default='Current',
help='Phase: Current, Planned, Final, or All',
choices=['Current', 'Planned', 'Final', 'All'])
pargs = parser.parse_args(args[2:])
HL.HLRelease(dirname=pargs.dir, phase=pargs.phase)
# Main Routine
if __name__ == '__main__':
parse(sys.argv)