summaryrefslogtreecommitdiffstats
path: root/build_tools/larch8/larch0/gui/project.py
diff options
context:
space:
mode:
Diffstat (limited to 'build_tools/larch8/larch0/gui/project.py')
-rw-r--r--build_tools/larch8/larch0/gui/project.py446
1 files changed, 446 insertions, 0 deletions
diff --git a/build_tools/larch8/larch0/gui/project.py b/build_tools/larch8/larch0/gui/project.py
new file mode 100644
index 0000000..6dc0000
--- /dev/null
+++ b/build_tools/larch8/larch0/gui/project.py
@@ -0,0 +1,446 @@
+# project.py - Project management
+#
+# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
+#
+# This file is part of the larch project.
+#
+# larch is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# larch is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with larch; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#----------------------------------------------------------------------------
+# 2010.10.24
+
+from config import *
+import os, shutil, pwd
+from glob import glob
+from subprocess import call
+from userinfo import Userinfo
+
+CONFIG_DIR = '.config/larch' # within the user's home directory
+APP_CONF = 'app.conf' # within larch config directory
+PROJECT_CONF = 'project.conf' # within project directory
+PROJECT0 = 'larch-0' # default project
+PROFILE0 = 'default' # default profile
+
+# Some default values for the project config file
+DEFAULTS = { 'installation_dir' : '',
+ 'pacman_cache' : '/var/cache/pacman/pkg',
+ 'profile' : PROFILE0,
+ 'profile_browse_dir': '', # => use default
+ 'installrepo' : '',
+ 'medium_iso' : '', # 'Yes' | ''
+ 'medium_search' : 'label', # 'search' | 'uuid' | 'label' | 'device'
+ 'boot_nosearch' : '', # 'Yes' | ''
+ 'do_persist' : 'Yes', # 'Yes' | ''
+ 'journal' : 'Yes', # 'Yes' | ''
+ 'medium_label' : '', # => fetch default
+ 'isosavedir' : '',
+ 'isofile' : '',
+ 'bootisofile' : '',
+ 'bootisolabel' : '',
+ 'do_format' : 'Yes', # 'Yes' | ''
+ }
+
+
+# Default values for the application config file
+APP_DEFAULTS = {
+ 'project' : PROJECT0,
+ 'filebrowser' : 'xdg-open $',
+ }
+
+
+
+class ProjectManager:
+ def __init__(self):
+ add_exports( (
+ ('getitem', self.getitem),
+ ('getbool', self.getbool),
+ ('setitem', self.setitem),
+ ('setbool', self.setbool),
+ ('get_projects', self.list_projects),
+ ('get_profiles', self.list_profiles),
+ ('get_installation_dir', self.get_ipath),
+ ('set_installation_dir', self.set_ipath),
+ ('testlarchify', self.testlarchify),
+ ('set_project', self.set_projectname),
+ ('get_project', self.get_projectname),
+ ('delete_project', self.delete_project),
+ ('delete_profile', self.delete_profile),
+ ('list_free_projects', self.list_free_projects),
+ ('list_free_profiles', self.list_free_profiles),
+ ('get_new_profile', self.get_new_profile),
+ ('rename_profile', self.rename_profile),
+ ('can_rename_profile', self.can_rename_profile),
+ ('save_profile', self.save_profile),
+ ('get_profile', self.get_profile),
+ ('set_profile', self.set_profile),
+ ('get_example_profiles', self.get_example_profiles),
+ ('set_profile_browse_dir', self.set_profile_browse_dir),
+ ('get_mediumlabel', self.get_mediumlabel),
+ ('set_mediumlabel', self.set_mediumlabel),
+ ('getisosavedir', self.getisosavedir),
+ ('getisofile', self.getisofile),
+ ('getbootisofile', self.getbootisofile),
+ ('get_bootisolabel', self.get_bootisolabel),
+ ('set_bootisolabel', self.set_bootisolabel),
+ ('newUserinfo', self.newUserinfo),
+ ('allusers', self.allusers),
+ ('getuserinfo', self.getuserinfo),
+ ('newuser', self.newuser),
+ ('userset', self.userset),
+ ('deluser', self.deluser),
+ ('listskels', self.listskels),
+ ('saveusers', self.saveusers))
+ )
+
+
+ def init(self):
+ self.projects_base = os.path.join(os.environ['HOME'], CONFIG_DIR)
+ self.profiles_dir = os.path.join(self.projects_base, 'myprofiles')
+ # Ensure the presence of the larch default project folder
+ dpf = '%s/p_%s' % (self.projects_base, PROJECT0)
+ if not os.path.isdir(dpf):
+ os.makedirs(dpf)
+ # Ensure the presence of the profiles folder and the 'default' profile
+ if not os.path.isdir(self.profiles_dir):
+ os.mkdir(self.profiles_dir)
+ self.default_profile_dir = os.path.join(self.profiles_dir, PROFILE0)
+ if not os.path.isdir(self.default_profile_dir):
+ call(['cp', '-a', base_dir + '/profiles/'+ PROFILE0,
+ self.profiles_dir])
+
+ # The application configs
+ self.aconfig_file = os.path.join(self.projects_base, APP_CONF)
+ self.aconfig = self.getconfig(self.aconfig_file)
+
+ # The project-specific configs
+ self.set_projectname(self.appget('project'))
+
+
+ def get_projectname(self):
+ return (True, self.project_name)
+
+ def set_projectname(self, name):
+ self.project_dir = os.path.join(self.projects_base, 'p_' + name)
+ plist = self.list_projects()[1]
+ if name not in plist:
+ os.mkdir(self.project_dir)
+
+ self.pconfig_file = os.path.join(self.project_dir, PROJECT_CONF)
+ self.pconfig = self.getconfig(self.pconfig_file)
+ self.profile_name = self.get('profile')
+
+ self.profile_path = os.path.join(self.profiles_dir, self.profile_name)
+ self.appset('project', name)
+ self.project_name = name
+ return (True, None)
+
+ def delete_project(self, name):
+ # This should probably be run as root, in case the build directory
+ # is inside it ... cross that bridge when we come to it!
+ r = call(['rm', '-r', '--interactive=never',
+ os.path.join(self.projects_base, 'p_' + name)])
+ return (True, r == 0)
+
+
+ def delete_profile(self, name):
+ r = call(['rm', '-r', '--interactive=never',
+ os.path.join(self.profiles_dir, name)])
+ return (True, r == 0)
+
+
+ def get_profile(self):
+ return (True, self.profile_name)
+
+ def set_profile(self, name):
+ self.set('profile', name)
+ self.profile_name = name
+ self.profile_path = os.path.join(self.profiles_dir, self.profile_name)
+ return (True, None)
+
+
+ def rename_profile(self, name):
+ os.rename(self.profile_path, os.path.join(self.profiles_dir, name))
+ self.set_profile(name)
+ return (True, None)
+
+
+ def get_new_profile(self, src, name):
+ if not os.path.isfile(src + '/addedpacks'):
+ return (True, False)
+ dst = os.path.join(self.profiles_dir, name)
+ call(['rm', '-rf', dst])
+ shutil.copytree(src, dst, symlinks=True)
+ self.set_profile(name)
+ return (True, True)
+
+
+ def get_example_profiles(self):
+ pd = base_dir + '/profiles'
+ return (True, (pd, os.listdir(pd)))
+
+# location of working profiles
+# self.projects_base + '/myprofiles',
+
+
+# What about not allowing changes to the default profile?
+# That would mean also no renaming?
+# One would have to copy a profile into the project before going
+# any further ...
+# Is it right to share profiles between projects? (Probably)
+
+#+++++++++++++++++++++++++++++++++++++++++++++++
+### A very simple configuration file handler
+ def getconfig(self, filepath):
+ cfg = {}
+ if os.path.isfile(filepath):
+ fh = open(filepath)
+ for line in fh:
+ ls = line.split('=', 1)
+ if len(ls) > 1:
+ cfg[ls[0].strip()] = ls[1].strip()
+ return cfg
+
+
+ def saveconfig(self, filepath, config):
+ fh = open(filepath, 'w')
+ ci = config.items()
+ ci.sort()
+ for kv in ci:
+ fh.write('%s = %s\n' % kv)
+ fh.close()
+###
+#-----------------------------------------------
+
+ def list_projects(self):
+ projects = [p[2:] for p in os.listdir(self.projects_base)
+ if p.startswith('p_')]
+ projects.sort()
+ return (True, projects)
+
+
+ def list_free_projects(self):
+ """This returns a list of projects which are free for (e.g.) deletion.
+ """
+ plist = self.list_projects()[1]
+ plist.remove(PROJECT0) # this one is not 'free'
+ if self.project_name in plist:
+ plist.remove(self.project_name)
+ return (True, plist)
+
+
+ def list_profiles(self):
+ profiles = [d for d in os.listdir(self.profiles_dir) if
+ os.path.isfile(os.path.join(self.profiles_dir, d, 'addedpacks'))]
+ profiles.sort()
+ return (True, profiles)
+
+
+ def list_free_profiles(self):
+ """This returns a list of profiles which are not in use by any project.
+ """
+ plist = self.list_profiles()[1]
+ plist.remove(PROFILE0) # this one is not 'free'
+ for project in self.list_projects()[1]:
+ cfg = self.getconfig(os.path.join(self.projects_base,
+ 'p_' + project, PROJECT_CONF))
+ p = cfg.get('profile')
+ if p in plist:
+ plist.remove(p)
+ return (True, plist)
+
+
+ def can_rename_profile(self):
+ if self.profile_name == PROFILE0:
+ return (True, False)
+ for project in self.list_projects()[1]:
+ if project != self.project_name:
+ cfg = self.getconfig(os.path.join(self.projects_base,
+ 'p_' + project, PROJECT_CONF))
+ if self.profile_name == cfg.get('profile'):
+ return (True, False)
+ return (True, True)
+
+
+ def save_profile(self, path, force):
+ if path[0] != '/':
+ # cloning, only the profile name is passed
+ path = os.path.join(self.profiles_dir, path)
+ else:
+ # copying, the destination will have the same name
+ if os.path.basename(path) != self.profile_name:
+ path = os.path.join(path, self.profile_name)
+ if os.path.exists(path):
+ if force:
+ call(['rm', '-rf', path])
+ elif os.path.isfile(os.path.join(path, 'addedpacks')):
+ # This is an existing profile
+ return (True, False)
+ else:
+ # This location is otherwise in use
+ return (True, None)
+ shutil.copytree(self.profile_path, path, symlinks=True)
+ return (True, True)
+
+
+ def set_profile_browse_dir(self, path):
+ if os.path.isfile(os.path.join(path, 'addedpacks')):
+ # Don't set the profile browse path to a profile directory,
+ # but rather tp the containing directory
+ path = os.path.dirname(path)
+ self.set('profile_browse_dir', path)
+
+
+ def appget(self, item):
+ """Read an entry in the application configuration.
+ """
+ v = self.aconfig.get(item)
+ if v:
+ return v
+ elif APP_DEFAULTS.has_key(item):
+ return APP_DEFAULTS[item]
+ debug("Unknown application configuration option: %s" % item)
+ assert False
+
+ def appset(self, item, value):
+ """Set an entry in the application configuration.
+ """
+ self.aconfig[item] = value.strip()
+ self.saveconfig(self.aconfig_file, self.aconfig)
+
+
+ def getitem(self, item):
+ return (True, self.get(item))
+
+ def getbool(self, item):
+ return (True, self.get(item) == 'Yes')
+
+ def setitem(self, item, value):
+ self.set(item, value)
+ return (True, None)
+
+ def setbool(self, item, on):
+ self.set(item, 'Yes' if on else 'No')
+ return (True, None)
+
+
+ def get(self, item):
+ """Read an entry in the project configuration.
+ """
+ v = self.pconfig.get(item)
+ if v:
+ return v
+ elif DEFAULTS.has_key(item):
+ return DEFAULTS[item]
+ debug("Unknown configuration option: %s" % item)
+ assert False
+
+ def set(self, item, value):
+ """Set an entry in the project configuration.
+ """
+ self.pconfig[item] = value.strip()
+ self.saveconfig(self.pconfig_file, self.pconfig)
+# return True
+
+
+ def get_ipath(self):
+ ip = self.get('installation_dir')
+ if not ip:
+ ip = self.set_ipath('')[1]
+ return (True, ip)
+
+ def set_ipath(self, path):
+ path = path.strip()
+ if path:
+ path = '/' + path.strip('/')
+ else:
+ path = os.environ['HOME'] + '/larch_build'
+ self.set('installation_dir', path)
+ return (True, path)
+
+
+ def testlarchify(self):
+ ipath = self.get_ipath()[1]
+ path = ipath + CHROOT_DIR_MEDIUM
+ bl = []
+ nosave = False
+ ok = (os.path.isfile(path + '/larch/system.sqf')
+ and os.path.isfile(ipath + SYSLINUXDIR + '/isolinux.bin'))
+ return (True, (path, ok))
+
+
+ def newUserinfo(self):
+ self.userInfo = Userinfo(self.profile_path)
+ return (True, None)
+
+ def allusers(self):
+ return (True, self.userInfo.allusers())
+
+ def getuserinfo(self, user, fields):
+ return (True, self.userInfo.userinfo(user, fields))
+
+ def newuser(self, user):
+ return (True, self.userInfo.newuser(user))
+
+ def saveusers(self):
+ return (True, self.userInfo.saveusers())
+
+ def userset(self, uname, field, text):
+ self.userInfo.userset(uname, field, text)
+ return (True, None)
+
+ def deluser(self, user):
+ return (True, self.userInfo.deluser(user))
+
+ def listskels(self):
+ return (True, glob(self.profile_path + '/skel_*'))
+
+
+ def get_mediumlabel(self):
+ l = self.get('medium_label')
+ return (True, l if l else LABEL)
+
+ def set_mediumlabel(self, l):
+ if len(l) > 16:
+ l = l[:16]
+ self.set('medium_label', l)
+ return self.get_mediumlabel()
+
+ def set_bootisolabel(self, l):
+ if len(l) > 32:
+ l = l[:32]
+ self.set('bootisolabel', l)
+ return self.get_mediumlabel()
+
+
+ def getisosavedir(self):
+ d = self.get('isosavedir')
+ return (True, d if d else os.environ['HOME'])
+
+ def getisofile(self):
+ f = self.get('isofile')
+ return (True, f if f else ISOFILE)
+
+ def getbootisofile(self):
+ f = self.get('bootisofile')
+ return (True, f if f else BOOTISO)
+
+ def get_bootisolabel(self):
+ l = self.get('bootisolabel')
+ return (True, l if l else BOOTISOLABEL)
+
+
+
+import __builtin__
+__builtin__.project_manager = ProjectManager()