Replaced project.json with info.yaml in places asking for basic project info. Renamed some variables that still referred to 'og.' Added create_yaml() method.
diff --git a/common/cace_datasheet_upload.py b/common/cace_datasheet_upload.py index 378dde9..171f325 100755 --- a/common/cace_datasheet_upload.py +++ b/common/cace_datasheet_upload.py
@@ -17,7 +17,7 @@ import file_compressor import file_request_hash -import og_config +import config """ Open Galaxy standalone script. @@ -27,7 +27,7 @@ has no other side effects. """ -mktp_server_url = og_config.mktp_server_url +mktp_server_url = config.mktp_server_url # Make request to server sending json passed in. def send_doc(doc):
diff --git a/common/cace_design_upload.py b/common/cace_design_upload.py index a783455..41e90f2 100755 --- a/common/cace_design_upload.py +++ b/common/cace_design_upload.py
@@ -19,7 +19,7 @@ import file_request_hash import local_uid_services -import og_config +import config """ Open Galaxy standalone script. @@ -30,8 +30,8 @@ on the CACE server. """ -mktp_server_url = og_config.mktp_server_url -cace_server_url = og_config.cace_server_url +mktp_server_url = config.mktp_server_url +cace_server_url = config.cace_server_url # Make request to server sending json passed in. def send_doc(doc): @@ -123,7 +123,7 @@ name = dsheet['ip-name'] # Get JSON file of settings if it exists. It should be in the same - # location as the JSON datasheet file (generated by og_gui_characterize.py) + # location as the JSON datasheet file (generated by cace.py) testmode = False force = False settings_filepath = os.path.split(datasheet_filepath)[0] + '/settings.json'
diff --git a/common/cace_gensim.py b/common/cace_gensim.py index be9007d..603b28a 100755 --- a/common/cace_gensim.py +++ b/common/cace_gensim.py
@@ -71,11 +71,11 @@ from spiceunits import spice_unit_convert from fix_libdirs import fix_libdirs -import og_config +import config -# Values obtained from og_config: +# Values obtained from config: # -apps_path = og_config.apps_path +apps_path = config.apps_path launchproc = [] def construct_dut_from_path(pname, pathname, pinlist, foundry, node):
diff --git a/common/cace_launch.py b/common/cace_launch.py index 8a17626..ed85b47 100755 --- a/common/cace_launch.py +++ b/common/cace_launch.py
@@ -31,13 +31,13 @@ import file_compressor import cace_makeplot -import og_config +import config -# Values imported from og_config: +# Values imported from config: # -mktp_server_url = og_config.mktp_server_url -# obs: og_server_url = og_config.og_server_url -simulation_path = og_config.simulation_path +mktp_server_url = config.mktp_server_url +# obs: og_server_url = config.og_server_url +simulation_path = config.simulation_path # Variables needing to be global until this file is properly made into a class simfiles_path = [] @@ -1185,7 +1185,7 @@ if root_path: simfiles_path = root_path + '/' + hashname else: - simfiles_path = og_config.simulation_path + '/' + hashname + simfiles_path = config.simulation_path + '/' + hashname if not os.path.isdir(simfiles_path): print('Error: Simulation folder ' + simfiles_path + ' does not exist.')
diff --git a/common/config.py b/common/config.py index ee9a986..a730732 100755 --- a/common/config.py +++ b/common/config.py
@@ -6,7 +6,7 @@ # default if fail to read/parse the etc file is STAGING. These values: # ef_variant=DEV ef_variant=STAGING ef_variant=PROD # yield respectively: -# import og_config_DEV import og_config_STAGING import og_config_PROD +# import config_DEV import config_STAGING import config_PROD # # Survive (try:) missing,improper,unreadable /etc/sysconfig/ef-config. # DO NOT survive (no try:) failed imports (non-existent file, bad syntax, etc.). @@ -27,7 +27,7 @@ ef_variant = config.get('null','ef_variant', fallback='STAGING').strip('\'"') # -# emulate: import og_config_<ef_variant> +# emulate: import config_<ef_variant> # -#cfgModule = __import__("og_config_"+ef_variant) +#cfgModule = __import__("config_"+ef_variant) #globals().update(vars(cfgModule))
diff --git a/common/create_project.py b/common/create_project.py index 125fcd3..764a166 100755 --- a/common/create_project.py +++ b/common/create_project.py
@@ -15,6 +15,7 @@ import re import sys import json +import yaml def usage(): print('Usage:') @@ -58,7 +59,7 @@ pdkpath = pdkname pdkname = os.path.split(pdkpath)[1] else: - pdkpath = os.path.join('PREFIX', 'pdk', pdkname) + pdkpath = os.path.join('/usr/share', 'pdk', pdkname) else: try: pdkpath = os.getenv()['PDK_PATH'] @@ -162,13 +163,25 @@ os.makedirs(ngspicepath) os.symlink(pdkpath + '/libs.tech/ngspice/spinit', ngspicepath + '/.spiceinit') - + + data = {} + project={} + project['description'] = "(Add project description here)" + + infofile = pdkpath + '/.config/nodeinfo.json' + if os.path.exists(infofile): + with open(infofile, 'r') as ifile: + nodeinfo = json.load(ifile) + if 'foundry' in nodeinfo: + project['foundry'] = nodeinfo['foundry'] + + project['process']=pdkname + project['project_name'] = projectname + data['project']=project + with open(projectpath + '/info.yaml', 'w') as ofile: print('---', file=ofile) - print('project:', file=ofile) - print(' description: "(Add project description here)"', file=ofile) - print(' process: "' + pdkname + '"', file=ofile) - print(' project_name: "' + projectname + '"', file=ofile) - + yaml.dump(data, ofile) + print('Done!') sys.exit(0)
diff --git a/common/foundry_nodes.py b/common/foundry_nodes.py index fba9132..b431eff 100755 --- a/common/foundry_nodes.py +++ b/common/foundry_nodes.py
@@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python # foundry_nodes.py --- #
diff --git a/common/profile.py b/common/profile.py index 6a46d22..befa426 100755 --- a/common/profile.py +++ b/common/profile.py
@@ -17,7 +17,7 @@ import subprocess from tkinter import ttk -import og_config +import config class Profile(tkinter.Toplevel): """Open Galaxy project manager profile settings management.""" @@ -77,7 +77,7 @@ userid = os.environ['USER'] ''' p = subprocess.run(['/ef/apps/bin/withnet', - og_config.apps_path + '/og_uid_service.py', userid], + config.apps_path + '/og_uid_service.py', userid], stdout = subprocess.PIPE) if p.stdout:
diff --git a/common/project_manager.py b/common/project_manager.py index 73ff0d8..17774d6 100755 --- a/common/project_manager.py +++ b/common/project_manager.py
@@ -435,13 +435,10 @@ # Only allow 'makeproject' checkbox if there is no project.json file jname = ppath + '/project.json' if not os.path.exists(jname): - dname = os.path.split(ppath)[1] - jname = ppath + '/' + dname + '.json' - if not os.path.exists(jname): - self.makeproject = ttk.Checkbutton(self.layoutbox, + self.makeproject = ttk.Checkbutton(self.layoutbox, text='Make default project name', variable = self.confirm) - self.makeproject.grid(row = 2, column = 0, columnspan = 2, sticky = 'ewns') + self.makeproject.grid(row = 2, column = 0, columnspan = 2, sticky = 'ewns') return self.layoutselect # initial focus def handle_choice(self, event): @@ -1080,7 +1077,7 @@ # #EFABLESS PLATFORM p = subprocess.run(['/ef/apps/bin/withnet' , - og_config.apps_path + '/og_uid_service.py', userid], + config.apps_path + '/og_uid_service.py', userid], stdout = subprocess.PIPE) if p.stdout: uid_string = p.stdout.splitlines()[0].decode('utf-8') @@ -1297,11 +1294,14 @@ description = '' status = 'active' if pdkdir: + # Code should only be for efabless platform + ''' split = os.path.split(os.path.realpath(pdkdir)) # Full path should be [<something>/]<foundry>[.ext]/<node> node = split[1] foundry = os.path.split(split[0])[1] foundry = os.path.splitext(foundry)[0] + ''' # Check for nodeinfo.json infofile = pdkdir + '/.config/nodeinfo.json' if os.path.exists(infofile): @@ -1437,6 +1437,13 @@ if os.path.isfile(root + ext): return root + ext return None + + def yaml2targz(self, yamlPath): + root = os.path.splitext(yamlPath)[0] + for ext in ('.tgz', '.tar.gz'): + if os.path.isfile(root + ext): + return root + ext + return None #------------------------------------------------------------------------ # Remove a .json and associated tar.gz (or .tgz) if any. @@ -1503,7 +1510,7 @@ if os.path.isdir(ipath): if os.path.islink(ipath) or not self.validProjectName(item) \ or self.importProjNameBadrex1.match(item) \ - or not os.path.isfile(ipath + '/project.json'): + or not os.path.isfile(ipath + '/info.yaml'): importlist.remove(item) continue else: @@ -1549,7 +1556,7 @@ # Import for json documents and related tarballs (.gz or .tgz): #------------------------------------------------------------------------ - def importjson(self, projname, importfile): + def importyaml(self, projname, importfile): # (1) Check if there is a tarball with the same root name as the JSON importroot = os.path.splitext(importfile)[0] badrex1 = re.compile("^\.") @@ -1585,29 +1592,18 @@ with tarfile.open(tarname, mode='r:gz') as archive: for member in archive: archive.extract(member, newproject) - # (5) Copy the JSON document into the new directory. Keep the + # (5) Copy the YAML document into the new directory. Keep the # original name of the project, so as to overwrite any existing # document, then change the name to match that of the project # folder. - # New behavior 12/2018: JSON file is always called 'project.json'. - # Also support legacy JSON name if it exists (don't generate files with - # both names) - jsonfile = newproject + '/project.json' - if not os.path.isfile(jsonfile): - if os.path.isfile(newproject + '/' + projname + '.json'): - jsonfile = newproject + '/' + projname + '.json' + yamlfile = newproject + '/info.yaml' try: - shutil.copy(importfile, jsonfile) + shutil.copy(importfile, yamlfile) except IOError as e: print('Error copying files: ' + str(e)) return None - else: - # If filename is 'project.json' then it does not need to be changed. - # This is for legacy name support only. - if jsonfile != newproject + '/project.json': - shutil.move(jsonfile, newproject + '/' + newname + '.json') # (6) Remove the original files from the import folder os.remove(importfile) @@ -1833,7 +1829,15 @@ if not tar: return None, None, None return self.tarVglImportable(tar) + + def yamlTarVglImportable(self, path): + ext = os.path.splitext(path)[1] + if ext != '.yaml': return None, None, None + tar = self.yaml2targz(path) + if not tar: return None, None, None + + return self.tarVglImportable(tar) #------------------------------------------------------------------------ # Get a single named member (memPath) out of a JSON's tar file. # This is thin wrapper around tarMember2tempfile. Find the JSON's associated @@ -1848,6 +1852,15 @@ if not tar: return None return self.tarMember2tempfile(tar, memPath) + + def yamlTarMember2tempfile(self, path, memPath): + ext = os.path.splitext(path)[1] + if ext != '.yaml': return None + + tar = self.yaml2targz(path) + if not tar: return None + + return self.tarMember2tempfile(tar, memPath) #------------------------------------------------------------------------ # Determine if tar-file can be imported as-if it were just a *.v. @@ -1978,13 +1991,16 @@ # necessary entries to define a project. jData = {} jDS = {} + ''' jDS['ip-name'] = ipname + pdkdir = self.get_pdk_dir(pname, path=True) try: jDS['foundry'], jDS['node'], pdk_desc, pdk_stat = self.pdkdir2fnd( pdkdir ) except: # Cannot parse PDK name, so foundry and node will remain undefined pass + ''' jDS['format'] = '3' pparams = [] param = {} @@ -2040,6 +2056,24 @@ return jData +#------------------------------------------------------------------------ + # Create info.yaml file (automatically done in create_project.py in case it's executed from the command line) + #------------------------------------------------------------------------ + + def create_yaml(self, ipname, pname, description="(Add project description here)"): + # ipname: Project Name + # pname: PDK directory + data = {} + project={} + project['description'] = description + try: + project['foundry'], project['process'], pdk_desc, pdk_stat = self.pdkdir2fnd( pname ) + except: + # Cannot parse PDK name, so foundry and node will remain undefined + pass + project['project_name'] = ipname + data['project']=project + return data #------------------------------------------------------------------------ # For a single named member (memPath) out of an open tarfile (tarf), # determine if it is a JSON file, and attempt to extract value of entry @@ -2400,6 +2434,7 @@ # Else PROMPT for new projectName and CREATE it (and use elecLib of same name). #------------------------------------------------------------------------ + def importvgl(self, newfile, importfile, newname=None, seedname=None): elecLib = None isnew = not newname @@ -2724,7 +2759,7 @@ if not confirm == 'okay': print('Warning: Must quit and restart to get any fixes or updates.') return - os.execl('/ef/efabless/opengalaxy/og_gui_manager.py', 'appsel_zenity.sh') + os.execl('/ef/efabless/opengalaxy/project_manager.py', 'appsel_zenity.sh') # Does not return; replaces existing process. #---------------------------------------------------------------------- @@ -2847,7 +2882,7 @@ try: - subprocess.Popen([config.apps_path + '/create_project.py', newproject, newpdk]) + subprocess.Popen([config.apps_path + '/create_project.py', newproject, newpdk]).wait() except IOError as e: print('Error copying files: ' + str(e)) @@ -2856,7 +2891,7 @@ except: print('Error making project.') return None - + return newname ''' # Find what tools are compatible with the given PDK @@ -3110,36 +3145,33 @@ print('Error copying files: ' + str(e)) return - # NOTE: Behavior is for project files to depend on "ip-name". Using + # NOTE: Behavior is for project files to depend on "project_name". Using # the project filename as a project name is a fallback behavior. If - # there is a project.json file, and it defines an ip-name entry, then + # there is a info.yaml file, and it defines a project_name entry, then # there is no need to make changes within the project. If there is - # no project.json file, then create one and set the ip-name entry to + # no info.yaml file, then create one and set the project_name entry to # the old project name, which avoids the need to make changes within # the project. else: - # Check project.json - jsonname = newproject + '/project.json' - legacyname = newproject + '/' + oldname + '.json' - if not os.path.isfile(jsonname): - if os.path.isfile(legacyname): - jsonname = legacyname + # Check info.yaml + yamlname = newproject + '/info.yaml' found = False - if os.path.isfile(jsonname): + if os.path.isfile(yamlname): # Pull the ipname into local store (may want to do this with the # datasheet as well) - with open(jsonname, 'r') as f: - datatop = json.load(f) - dsheet = datatop['data-sheet'] - if 'ip-name' in dsheet: + with open(yamlname, 'r') as f: + datatop = yaml.safe_load(f) + if 'project_name' in datatop['project']: found = True if not found: - jData = self.create_ad_hoc_json(oldname, newproject) - with open(newproject + '/project.json', 'w') as ofile: - json.dump(jData, ofile, indent = 4) + pdkdir = self.get_pdk_dir(newproject, path=True) + yData = self.create_yaml(oldname, pdkdir) + with open(newproject + '/info.yaml', 'w') as ofile: + print('---',file=ofile) + yaml.dump(yData, ofile) # If ngspice and electric prefs were not copied from the source # to the target, as recommended, then copy these from the @@ -3174,27 +3206,23 @@ badrex2 = re.compile(".*[/ \t\n\\\><\*\?].*") projname = value['text'] - # Find the IP name for project projname. If it has a JSON file, then + # Find the IP name for project projname. If it has a YAML file, then # read it and pull the ip-name record. If not, the fallback position # is to assume that the project filename is the project name. - # Check project.json + # Check info.yaml projectpath = self.projectdir + '/' + projname - jsonname = projectpath + '/project.json' - legacyname = projectpath + '/' + projname + '.json' - if not os.path.isfile(jsonname): - if os.path.isfile(legacyname): - jsonname = legacyname + yamlname = projectpath + '/info.yaml' oldname = projname - if os.path.isfile(jsonname): + if os.path.isfile(yamlname): # Pull the ipname into local store (may want to do this with the # datasheet as well) - with open(jsonname, 'r') as f: - datatop = json.load(f) - dsheet = datatop['data-sheet'] - if 'ip-name' in dsheet: - oldname = dsheet['ip-name'] + with open(yamlname, 'r') as f: + datatop = yaml.safe_load(f) + project_data = datatop['project'] + if 'project_name' in project_data: + oldname = project_data['project_name'] warning = 'Rename IP "' + oldname + '" for project ' + projname + ':' print(warning) @@ -3962,7 +3990,7 @@ designname = self.project_name print('Upload design ' + designname + ' (' + design + ' )') subprocess.run(['/ef/apps/bin/withnet', - og_config.apps_path + '/cace_design_upload.py', + config.apps_path + '/cace_design_upload.py', design, '-test']) ''' @@ -3973,7 +4001,7 @@ # def make_challenge(self): # importp = self.cur_import # print("Make a Challenge from import " + importp + "!") - # # subprocess.run([og_config.apps_path + '/cace_import_upload.py', importp, '-test']) + # # subprocess.run([config.apps_path + '/cace_import_upload.py', importp, '-test']) def setcurrent(self, value): global currdesign @@ -4061,27 +4089,28 @@ # it. # NOTE: project.json is the preferred name for the datasheet # file. However, the .spi file, .delib file, etc., all have the name of the - # project from "ip-name" in the datasheet. - # "<project_folder_name>.json" is the legacy name for the datasheet, deprecated. + # project from "project_name" in the info.yaml file, which is separate from the datasheet. found = False ppath = selection['values'][0] + yamlname = ppath + '/info.yaml' + + if os.path.isfile(yamlname): + # Pull the project_name into local store + with open(yamlname, 'r') as f: + datatop = yaml.safe_load(f) + project_data = datatop['project'] + ipname = project_data['project_name'] + self.project_name = ipname + else: + print('Setting project ip-name from the project folder name.') + self.project_name = pname jsonname = ppath + '/project.json' - legacyname = ppath + '/' + pname + '.json' - if not os.path.isfile(jsonname): - if os.path.isfile(legacyname): - jsonname = legacyname - if os.path.isfile(jsonname): - # Pull the ipname into local store (may want to do this with the - # datasheet as well) with open(jsonname, 'r') as f: datatop = json.load(f) dsheet = datatop['data-sheet'] - ipname = dsheet['ip-name'] - self.project_name = ipname found = True - # Do not specifically prohibit opening the characterization app if # there is no schematic or netlist. Otherwise the user is prevented # even from seeing the electrical parameters. Let the characterization @@ -4097,8 +4126,6 @@ else: # Use 'pname' as the default project name. print('No characterization file ' + jsonname) - print('Setting project ip-name from the project folder name.') - self.project_name = pname # If datasheet has physical parameters but not electrical parameters, then it's okay # for it not to have a testbench directory; it's still valid. However, having