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