aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevan Franchini <twitch153@gentoo.org>2014-08-10 21:00:49 -0400
committerDevan Franchini <twitch153@gentoo.org>2014-08-15 17:42:41 -0400
commitc3b6f7c9de1bd5723cd132e2ed66a9e8e557f22a (patch)
treeea0f12be371995c79b365e67df28ddc04466c3e3
parentMigrates run_command to utily.py (diff)
downloadlayman-c3b6f7c9de1bd5723cd132e2ed66a9e8e557f22a.tar.gz
layman-c3b6f7c9de1bd5723cd132e2ed66a9e8e557f22a.tar.bz2
layman-c3b6f7c9de1bd5723cd132e2ed66a9e8e557f22a.zip
Adds layman-mounter utility script
api.py: Adds Mounter() initialization in the LaymanAPI. constants.py: Adds MOUNT_TYPES to constants to keep track of mountable overlay classes. archive.py: Adds check to unmount overlays if they are being synced.
-rwxr-xr-xbin/layman-mounter42
-rwxr-xr-xlayman/api.py5
-rw-r--r--layman/constants.py9
-rw-r--r--layman/mounter.py313
-rw-r--r--layman/overlays/archive.py5
5 files changed, 373 insertions, 1 deletions
diff --git a/bin/layman-mounter b/bin/layman-mounter
new file mode 100755
index 0000000..cd41078
--- /dev/null
+++ b/bin/layman-mounter
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+################################################################################
+# LAYMAN - A UTILITY TO HANDLE MOUNTING OVERLAYS
+################################################################################
+# Distributed under the terms of the GNU General Public License v2
+#
+# Copyright:
+# (c) 2014 Devan Franchini
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Devan Franchini <twitch153@gentoo.org>
+#
+
+__version__ = "0.1"
+
+#===============================================================================
+#
+# Dependencies
+#
+#-------------------------------------------------------------------------------
+
+from layman.api import LaymanAPI
+from layman.config import OptionConfig
+from layman.mounter import Interactive
+
+#===============================================================================
+#
+# MAIN
+#
+#-------------------------------------------------------------------------------
+
+config = OptionConfig()
+layman_api = LaymanAPI(config,
+ report_errors=True,
+ output=config['output'])
+
+main = Interactive(config=config, mounter=config['mounts'])
+main()
+
diff --git a/layman/api.py b/layman/api.py
index bae6972..0f43f28 100755
--- a/layman/api.py
+++ b/layman/api.py
@@ -27,6 +27,7 @@ from layman.overlays.source import require_supported
#from layman.utils import path, delete_empty_directory
from layman.compatibility import encode
from layman.utils import verify_overlay_src
+from layman.mounter import Mounter
if sys.hexversion >= 0x30200f0:
STR = str
@@ -68,6 +69,10 @@ class LaymanAPI(object):
self._error_messages = []
self.sync_results = []
+ self.config.set_option('mounts', Mounter(self._get_installed_db,
+ self.get_installed,
+ config=self.config))
+
def is_repo(self, ovl):
"""validates that the ovl given is a known repo id
diff --git a/layman/constants.py b/layman/constants.py
index c526cb6..7379429 100644
--- a/layman/constants.py
+++ b/layman/constants.py
@@ -67,7 +67,6 @@ COMPONENT_DEFAULTS = ['name', 'descriptions', 'owner', 'type', 'sources']
POSSIBLE_COMPONENTS = ['name', 'descriptions', 'homepage', 'owner', 'quality',
'priority', 'sources', 'branch', 'irc', 'feeds']
-
###############################################################################
##
## Archive overlay possible file extensions
@@ -77,3 +76,11 @@ POSSIBLE_COMPONENTS = ['name', 'descriptions', 'homepage', 'owner', 'quality',
FILE_EXTENSIONS = {'Tar': ('bz2', 'gz', 'lzma', 'xz', 'Z', 'tgz', 'tbz', 'taz',
'tlz', 'txz')
}
+
+###################################################################################
+##
+## Overlay types mountable by script
+##
+####################################################################################
+
+MOUNT_TYPES = []
diff --git a/layman/mounter.py b/layman/mounter.py
new file mode 100644
index 0000000..f041a9a
--- /dev/null
+++ b/layman/mounter.py
@@ -0,0 +1,313 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+###############################################################################
+# LAYMAN MOUNTING OVERLAY HANDLER
+###############################################################################
+# File: mounter.py
+#
+# Controls all mountable overlay types
+#
+# Copyright:
+# (c) 2014 Devan Franchini
+# Distributed under the terms of the GNU General Public License v2
+#
+# Author(s):
+# Devan Franchini <twitch153@gentoo.org>
+#
+'''
+Controls all mountable overlay types.
+'''
+#==============================================================================
+#
+# Dependencies
+#
+#------------------------------------------------------------------------------
+from __future__ import unicode_literals
+
+import argparse
+import copy
+import os
+import sys
+
+from layman.constants import MOUNT_TYPES
+from layman.utils import path, run_command
+from layman.version import VERSION
+
+
+if sys.hexversion >= 0x30200f0:
+ STR = str
+else:
+ STR = basestring
+
+MOUNT_ARGS = {'Squashfs': ['-o', 'loop', '-t', 'squashfs']}
+_USAGE = 'layman-mounter [-h] [-l] [-L] [-m MOUNT [MOUNT ...]]\n'\
+ ' [-u UMOUNT [UMOUNT ...]] [-V]'
+
+def is_mounted(mdir):
+ '''
+ Determines whether or not an overlay is mounted at it's
+ installed overlay.
+
+ @rtype bool
+ '''
+ return os.path.ismount(mdir)
+
+
+class Mounter(object):
+ '''
+ Handles all mountable overlays.
+ '''
+ def __init__(self, database, overlays, config=None):
+ self.config = config
+ self.database = database
+ self.output = self.config['output']
+ self.overlays = overlays
+ self.storage = self.config['storage']
+
+
+ @property
+ def installed(self):
+ '''
+ Returns a dictionary of all installed overlays
+ and their overlay objects.
+
+ @rtype dict {'ovl1', <layman.overlays.Overlay object>,...}
+ '''
+ installed_db = {}
+
+ for overlay in self.overlays():
+ ovl_db = self.database().select(overlay)
+ installed_db[overlay] = ovl_db
+ return installed_db
+
+
+ @property
+ def mountables(self):
+ '''
+ Returns a dictionary of all mountable overlays and their
+ types.
+
+ @rtype dict {'ovl1': 'Squashfs',...}
+ '''
+ mountable_ovls = {}
+
+ for key in sorted(self.installed):
+ for ovl_type in self.installed[key].source_types():
+ if ovl_type in MOUNT_TYPES:
+ mountable_ovls[key] = ovl_type
+ return mountable_ovls
+
+
+ @property
+ def mounted(self):
+ '''
+ Returns a dictionary of all mountable overlays and a
+ boolean reflecting their mounted status.
+
+ @rtype dict {'ovl1': True, 'ovl2': False,...}
+ '''
+ mounted_ovls = {}
+
+ for ovl in self.mountables:
+ mdir = path([self.storage, ovl])
+ mounted_ovls[ovl] = is_mounted(mdir)
+ return mounted_ovls
+
+
+ def _check_selection(self, repos):
+ '''
+ Internal function to validate the repo parameter.
+
+ @rtype tuple
+ '''
+ if 'ALL' in repo:
+ repos = sorted(self.mountables)
+ elif isinstance(repos, STR):
+ repos = [repos]
+
+ return repos
+
+
+ def mount(self, repo, dest=None, install=False, ovl_type=None, pkg=None):
+ '''
+ Mounts an overlay to it's installation directory.
+
+ @params repo: str of overlay name or "ALL".
+ @params dest: str of optional destination dir.
+ @params install: bool to reflect whether or not the overlay is being
+ installed.
+ @params ovl_type: str of optional overlay type.
+ @params pkg: str of optional location of package to mount.
+ @rtype int: reflects whether or not the overlay was mounted.
+ '''
+ result = 1
+
+ selection = self._check_selection(repo)
+
+ for i in selection:
+ name = {'ovl': i}
+
+ if i not in self.mountables and not install:
+ self.output.error('Overlay "%(ovl)s" cannot be mounted!'\
+ % name)
+ continue
+ if dest:
+ mdir = dest
+ else:
+ mdir = path([self.storage, i])
+
+ if not is_mounted(mdir):
+ if install:
+ args = copy.deepcopy(MOUNT_ARGS[ovl_type])
+ else:
+ args = copy.deepcopy(MOUNT_ARGS[self.mountables[i]])
+
+ if not pkg:
+ source = self.installed[i].sources[0].src
+
+ if 'file://' in source:
+ pkg = source.replace('file://', '')
+ else:
+ pkg = path([self.storage, i, source.get_extension()])
+
+ args.append(pkg)
+ args.append(mdir)
+ result = run_command(self.config, 'mount', args, cmd='mount')
+ else:
+ self.output.warn('Overlay "%(ovl)s" is already mounted!'\
+ % name)
+ return result
+
+
+ def umount(self, repo, dest=None, sync=False):
+ '''
+ Unmounts an overlay from it's installation directory.
+
+ @params repo: str of overlay name or "ALL".
+ @params dest: str of optional path to unmount.
+ @params sync: bool to reflect whether or not the overlay is being
+ synced.
+ @rtype int: reflects whether or not it was a successful unmount.
+ '''
+ result = 1
+
+ selection = self._check_selection(repo)
+
+ for i in selection:
+ name = {'ovl': i}
+
+ if i not in self.mountables and not sync:
+ self.output.error('Overlay "%(ovl)s" cannot be mounted!'\
+ % name)
+ continue
+ if dest:
+ mdir = dest
+ else:
+ mdir = path([self.storage, i])
+
+ if is_mounted(mdir):
+ args = ['-l', mdir]
+ result = run_command(self.config, 'umount', args, cmd='umount')
+ else:
+ self.output.warn('Overlay "%(ovl)s" is already unmounted!'\
+ % name)
+
+ return result
+
+
+class Interactive(object):
+ '''
+ Interactive CLI session for the Mounter class
+ '''
+ def __init__(self, config=None, mounter=None):
+ self.args = None
+ self.parser = None
+ self.output = config['output']
+ self.storage = config['storage']
+ self.mount = mounter
+ self.mountables = self.mount.mountables
+
+
+ def args_parser(self):
+ '''
+ Parses all command line arguments.
+
+ @rtype argparse.NameSpace object.
+ '''
+ self.parser = argparse.ArgumentParser(prog='layman-mounter',
+ description='Layman\'s utility script to handle mountable '\
+ 'overlays.')
+ self.parser.add_argument('-l',
+ '--list-mountables',
+ action='store_true',
+ help='Lists all available overlays that'
+ ' support mounting')
+ self.parser.add_argument('-L',
+ '--list-mounted',
+ action='store_true',
+ help='Lists all mounted overlays')
+ self.parser.add_argument('-m',
+ '--mount',
+ nargs='+',
+ help='Mounts the selected overlay. Specify '\
+ '"ALL" to mount all possible overlays')
+ self.parser.add_argument('-u',
+ '--umount',
+ nargs='+',
+ help='Unmounts the selected overlay. Specify'\
+ ' "ALL" to unmount all possible overlays')
+ self.parser.add_argument('-V',
+ '--version',
+ action='version',
+ version='%(prog)s ' + VERSION)
+ self.args = self.parser.parse_args()
+
+
+ def __call__(self):
+ self.args_parser()
+ if len(sys.argv) == 1:
+ self.output.notice('usage: %(USAGE)s' % {'USAGE':_USAGE})
+ sys.exit(0)
+ options = {}
+
+ for key in vars(self.args):
+ options[key] = vars(self.args)[key]
+
+ for i in ('list_mountables', 'list_mounted'):
+ if options[i]:
+ getattr(self, i)()
+ self.output.notice('')
+
+ for i in ('umount', 'mount'):
+ if options[i]:
+ getattr(self.mount, '%(action)s' % {'action': i})(options[i])
+
+
+ def list_mountables(self):
+ '''
+ Lists all overlays that can be mounted.
+ '''
+ self.output.info('Mountable overlays:')
+ self.output.info('~~~~~~~~~~~~~~~~~~~')
+ if self.mountables:
+ for ovl in sorted(self.mountables):
+ self.output.info(ovl)
+ else:
+ self.output.warn('N/A')
+
+
+ def list_mounted(self):
+ '''
+ Lists all mounted overlays.
+ '''
+ mounted = self.mount.mounted
+
+ self.output.info('Overlays:')
+ self.output.info('~~~~~~~~~')
+ for i in mounted:
+ if mounted[i]:
+ status = 'Mounted'
+ else:
+ status = 'Unmounted'
+ stat_dict = {'ovl': i, 'status': status}
+ self.output.info('Name: %(ovl)s, Status: %(status)s' % stat_dict)
diff --git a/layman/overlays/archive.py b/layman/overlays/archive.py
index 68c8b47..b1907ee 100644
--- a/layman/overlays/archive.py
+++ b/layman/overlays/archive.py
@@ -98,6 +98,11 @@ class ArchiveOverlay(OverlaySource):
temp_path = final_path
if not os.path.exists(temp_path):
os.mkdir(temp_path)
+ else:
+ if os.path.ismount(temp_path):
+ self.config['mounts'].umount([self.parent.name],
+ dest=temp_path,
+ sync=True)
pkg = self._fetch(base=base, archive_url=self.src,
dest_dir=temp_path)
result = self.post_fetch(pkg, temp_path)