public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/overlay/pkgdir/symlink/
Date: Mon, 28 Jan 2013 23:54:06 +0000 (UTC)	[thread overview]
Message-ID: <1359416224.d9996361f71ec129746861e4c312d20bfb92230a.dywi@gentoo> (raw)

commit:     d9996361f71ec129746861e4c312d20bfb92230a
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Mon Jan 28 22:41:30 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Mon Jan 28 23:37:04 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d9996361

roverlay/overlay/pkgdir: SymlinkDistroot/dir

A SymlinkDistroot manages zero or more per-package SymlinkDistdirs that
contain symlinks to the R package files.
Used for Manifest file creation.

---
 roverlay/overlay/pkgdir/symlink/__init__.py |    5 +
 roverlay/overlay/pkgdir/symlink/distdir.py  |   47 ++++++
 roverlay/overlay/pkgdir/symlink/distroot.py |  234 +++++++++++++++++++++++++++
 3 files changed, 286 insertions(+), 0 deletions(-)

diff --git a/roverlay/overlay/pkgdir/symlink/__init__.py b/roverlay/overlay/pkgdir/symlink/__init__.py
new file mode 100644
index 0000000..a7f7e7d
--- /dev/null
+++ b/roverlay/overlay/pkgdir/symlink/__init__.py
@@ -0,0 +1,5 @@
+# R overlay -- overlay package, symlink directories
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.

diff --git a/roverlay/overlay/pkgdir/symlink/distdir.py b/roverlay/overlay/pkgdir/symlink/distdir.py
new file mode 100644
index 0000000..cca9b31
--- /dev/null
+++ b/roverlay/overlay/pkgdir/symlink/distdir.py
@@ -0,0 +1,47 @@
+# R overlay -- overlay package, symlink distdir
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+import os
+
+__all__ = [ 'SymlinkDistdir', ]
+
+class SymlinkDistdir ( object ):
+
+	def __init__ ( self, root ):
+		"""Initializes a symlink DISTDIR.
+
+		arguments:
+		* root -- directory where symlinks will be created
+		"""
+		self.root = root
+		if not os.path.isdir ( self.root ):
+			os.mkdir ( self.root )
+	# --- end of __init__ (...) ---
+
+	def add ( self, fpath, fname=None ):
+		"""Adds a symlink to a file to this dir.
+
+		arguments:
+		* fpath -- path to the file for which a symlink will be created
+		* fname -- name of the symlink, defaults to os.path.basename ( fpath )
+		"""
+		symlink = self.root + os.sep + ( fname or os.path.basename ( fpath ) )
+
+		if os.path.lexists ( symlink ):
+			os.unlink ( symlink )
+
+		if not os.path.exists ( symlink ):
+			os.symlink ( fpath, symlink )
+			return symlink
+		else:
+			raise OSError ( "cannot set up symlink {!r}!".format ( symlink ) )
+	# --- end of add (...) ---
+
+	def __str__ ( self ):
+		return self.root
+	# --- end of __str__ (...) ---
+
+# --- end of SymlinkDistdir ---

diff --git a/roverlay/overlay/pkgdir/symlink/distroot.py b/roverlay/overlay/pkgdir/symlink/distroot.py
new file mode 100644
index 0000000..7345d98
--- /dev/null
+++ b/roverlay/overlay/pkgdir/symlink/distroot.py
@@ -0,0 +1,234 @@
+# R overlay -- overlay package, symlink distroot
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+__all__ = [ 'SymlinkDistroot', 'ThreadsafeSymlinkDistroot' ]
+
+import os
+import atexit
+import shutil
+import tempfile
+import threading
+import logging
+
+import roverlay.config
+
+import roverlay.overlay.pkgdir.symlink.distdir
+
+class _SymlinkDistrootBase ( object ):
+
+	_instance_lock = threading.Lock()
+	__instance     = None
+
+	@classmethod
+	def get_configured ( cls ):
+		"""Returns the static SymlinkDistroot instance."""
+		if cls.__instance is None:
+			with cls._instance_lock:
+				if cls.__instance is None:
+					cls.__instance = cls (
+						root = roverlay.config.get (
+							'OVERLAY.SYMLINK_DISTROOT.root', ""
+						),
+						is_tmpdir = roverlay.config.get_or_fail (
+							'OVERLAY.SYMLINK_DISTROOT.tmp'
+						),
+					)
+		return cls.__instance
+	# --- end of get_configured (...) ---
+
+	def __repr__ ( self ):
+		return "{}<root={}, tmpdir={}>".format (
+			self.__class__.__name__, self._root, self._is_tmpdir
+		)
+	# --- end of __repr__ (...) ---
+
+	def __str__ ( self ):
+		return str ( self._root )
+	# --- end of __str__ (...) ---
+
+	def __init__ ( self, root, is_tmpdir ):
+		"""Initializes a _SymlinkDistrootBase instance.
+
+		arguments:
+		* root      -- root directory where per-package SymlinkDistdirs will
+		               be created. An empty value is only valid if is_tmpdir
+		               evaluates to True.
+		* is_tmpdir -- whether this SymlinkDistroot is a temporary directory
+		               or not. A temporary directory will be wiped at exit,
+		               while a non-temporary one will only be cleaned up.
+
+		tempfile.mktempd() will be used as directory if root is empty
+		and is_tmpdir is true.
+
+		Raises: ConfigError if root is not set and is_tmpdir evaluates to False.
+		"""
+		super ( _SymlinkDistrootBase, self ).__init__()
+
+		self._root      = root
+		self._is_tmpdir = bool ( is_tmpdir )
+
+		if not self._root:
+			if self._is_tmpdir:
+				self._root = tempfile.mkdtemp ( prefix='tmp_roverlay_sym' )
+			else:
+				raise roverlay.config.ConfigError (
+					"OVERLAY.symlink_distroot: invalid value."
+				)
+		elif not os.path.isdir ( self._root ):
+			os.makedirs ( self._root, 0o755 )
+
+		self._prepare()
+
+		atexit.register ( self._destroy if self._is_tmpdir else self._cleanup )
+	# --- end of __init__ (...) ---
+
+	def _cleanup ( self ):
+		"""Cleans up a SymlinkDistroot."""
+		# derived classes can implement this to define actions for non-temporary
+		# SymlinkDistroots  that will be performed at ext.
+		pass
+	# --- end of _cleanup (...) ---
+
+	def _destroy ( self, force=False ):
+		"""Destroys a SymlinkDistroot.
+
+		arguments:
+		* force -- force destruction even if this distroot is not temporary
+		"""
+		if force or self._is_tmpdir:
+			shutil.rmtree ( self._root )
+	# --- end of _destroy (...) ---
+
+	def _get ( self, package_name ):
+		"""Returns a new SymlinkDistdir instance for given package.
+
+		arguments:
+		* package_name -- will be used as subdirectory name and must not
+		                  contain any os.sep chars (typically "/")
+		"""
+		assert os.sep not in package_name
+		return roverlay.overlay.pkgdir.symlink.distdir.SymlinkDistdir (
+			self._root + os.sep + package_name
+		)
+	# --- end of get (...) ---
+
+	def _prepare ( self ):
+		"""Prepares the SymlinkDistroot. Called for both temporary and
+		persistent distroots.
+
+		The default actions is to remove broken symlinks.
+		"""
+		if not self._is_tmpdir:
+			self.remove_broken_symlinks ( unsafe_assumptions=True )
+	# --- end of _prepare (...) ---
+
+	def get ( self, package_name ):
+		"""Returns a SymlinkDistdir for the given package.
+
+		arguments:
+		* package_name
+
+		Has to be implemented by derived classes.
+		"""
+		raise NotImplementedError()
+	# --- end of get (...) ---
+
+	def remove_broken_symlinks ( self, unsafe_assumptions=False ):
+		"""Recursively remove broken/dead symlinks.
+
+		arguments:
+		* unsafe_assumptions -- use (potentially) faster but less safe code
+		"""
+		def recursive_remove ( root, rmdir ):
+			for item in os.listdir ( root ):
+				fpath = root + os.sep + item
+
+				if not os.path.exists ( fpath ):
+					os.unlink ( fpath )
+
+				elif os.path.isdir ( fpath ):
+					recursive_remove ( fpath, True )
+					if rmdir:
+						try:
+							os.rmdir ( fpath )
+						except OSError:
+							pass
+		# --- end of recursive_remove (...) ---
+
+		if unsafe_assumptions:
+			# completely "unroll" the recursion using the following assumptions:
+			# * self._root contains directories only
+			# * maximum recursion depth is 1 (no nested subdir structure)
+
+			for d_item in os.listdir ( self._root ):
+				d_path = self._root + os.sep + d_item
+
+				for l_item in os.listdir ( d_path ):
+					l_path = self._root + os.sep + l_item
+					if not os.path.exists ( l_path ):
+						os.unlink ( l_path )
+
+				try:
+					os.rmdir ( dpath )
+				except OSError:
+					pass
+		else:
+			recursive_remove ( self._root, False )
+
+	# --- end of remove_broken_symlinks (...) ---
+
+# --- end of _SymlinkDistrootBase ---
+
+class SymlinkDistroot ( _SymlinkDistrootBase ):
+	"""A symlink distroot that uses a dict to remember
+	per-package SymlinkDistdirs.
+	"""
+
+	# _not_ threadsafe, but get() is expected to be called
+	#  within a (per-package_name) threadsafe context
+
+	def __init__ ( self, *args, **kwargs ):
+		"""see _SymlinkDistrootBase.__init__()"""
+		super ( SymlinkDistroot, self ).__init__ ( *args, **kwargs )
+		self._subdirs = dict()
+	# --- end of __init__ (...) ---
+
+	def get ( self, package_name ):
+		"""Returns a SymlinkDistdir for the given package.
+
+		arguments:
+		* package_name --
+		"""
+		try:
+			return self._subdirs [package_name]
+		except KeyError:
+			self._subdirs [package_name] = self._get ( package_name )
+			return self._subdirs [package_name]
+	# --- end of get (...) ---
+
+# --- end of SymlinkDistroot ---
+
+class ThreadsafeSymlinkDistroot ( SymlinkDistroot ):
+	"""Like SymlinkDistroot, but locks while creating SymlinkDistdirs."""
+
+	# will be removed if SymlinkDistroot is sufficient.
+
+	def __init__ ( self, *args, **kwargs ):
+		super ( ThreadsafeSymlinkDistroot, self ).__init__ ( *args, **kwargs )
+		self._lock = threading.Lock()
+	# --- end of __init__ (...) ---
+
+	def get ( self, package_name ):
+		try:
+			return self._subdirs [package_name]
+		except KeyError:
+			with self._lock:
+				if package_name not in self._subdirs:
+					self._subdirs [package_name] = self._get ( package_name )
+			return self._subdirs [package_name]
+	# --- end of get (...) ---
+
+# --- end of ThreadsafeSymlinkDistroot ---


             reply	other threads:[~2013-01-28 23:54 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-28 23:54 André Erdmann [this message]
  -- strict thread matches above, loose matches on Subject: below --
2013-02-05 20:54 [gentoo-commits] proj/R_overlay:master commit in: roverlay/overlay/pkgdir/symlink/ André Erdmann

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1359416224.d9996361f71ec129746861e4c312d20bfb92230a.dywi@gentoo \
    --to=dywi@mailerd.de \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox