[103407] users/cal/base-sqlite-portindex/src/portindex1.0

cal at macports.org cal at macports.org
Sun Feb 24 17:14:41 PST 2013


Revision: 103407
          https://trac.macports.org/changeset/103407
Author:   cal at macports.org
Date:     2013-02-24 17:14:41 -0800 (Sun, 24 Feb 2013)
Log Message:
-----------
SQLite portindex: start abstraction of portindex reading

Modified Paths:
--------------
    users/cal/base-sqlite-portindex/src/portindex1.0/portindex.tcl
    users/cal/base-sqlite-portindex/src/portindex1.0/sqlite.tcl

Modified: users/cal/base-sqlite-portindex/src/portindex1.0/portindex.tcl
===================================================================
--- users/cal/base-sqlite-portindex/src/portindex1.0/portindex.tcl	2013-02-24 23:11:50 UTC (rev 103406)
+++ users/cal/base-sqlite-portindex/src/portindex1.0/portindex.tcl	2013-02-25 01:14:41 UTC (rev 103407)
@@ -40,6 +40,14 @@
 	# The type of the PortIndex implementation
 	variable portindex_type ""
 
+	# A map from path to open PortIndex
+	variable portindex_map
+	array set portindex_map {}
+
+	# A map from path to PortIndex retain count 
+	variable portindex_retain_count
+	array set portindex_retain_count {}
+
 	# Number of total ports processed in this index operation
 	variable count_total  0
 	# Number of ports that were processed but failed
@@ -59,7 +67,7 @@
 				# do nothing, those are valid types
 			}
 			default {
-				error "portindex::set_portindex_type called with invalid type \
+				error "portindex::set_portindex_type called with invalid type\
 					${type}. Valid types are: sqlite, tcl."
 			}
 		}
@@ -71,6 +79,98 @@
 		set portindex_type ${type}
 	}
 
+	# Returns a handle that can be used to query the PortIndex in the given
+	# path. Automatically selects the best available index type. Raises an
+	# error, if no index can be found.
+	# Use the handle returned by this procedure to query the portindex, by
+	# calling the methods available in portindex::${type}. Do not use this
+	# handle to modify the portindex.
+	proc open {path} {
+		variable portindex_map
+		variable portindex_retain_count
+
+		# Some sanity checks to fail early
+		if {![file exists ${path}]} {
+			error "No PortIndex found at ${path}: No such file or directory"
+		}
+		if {![file isdirectory ${path}]} {
+			error "No PortIndex found at ${path}: Not a directory"
+		}
+
+		# Check for existing PortIndex commands for this path
+		if {[info exists portindex_map($path)]} {
+			incr $portindex_retain_count($path)
+			return $portindex_map($path)
+		}
+
+		# This list defines the priority of PortIndex implementations
+		foreach type [list sqlite tcl] {
+			if {[eval ${type}::seems_like_valid_portindex ${path}]} {
+				# Found the type of PortIndex we want
+				set portindex_map($path) [create_portindex_handle ${type} ${path}]
+				set portindex_retain_count($path) 1
+				return $portindex_map($path)
+			}
+		}
+
+		# No index found
+        error "No index(es) found! Have you synced your port definitions?\
+			Try running 'port selfupdate'."
+	}
+
+	# Creates and returns a new handle that can be used like $handle command to
+	# call portindex::${type}::${command} ${path} and pass along all further
+	# arguments.
+	# After usage, this handle should be released using `$handle release`.
+	proc create_portindex_handle {type path} {
+		# Similar to what we used in registry2.0, this finds a unique command
+		# name to be used as a handle for this specific instance of the
+		# PortIndex. This is the poor man's way of OO.
+		set cmdname ""
+		for {set i 0} {$i < 1000} {incr i} {
+			if {[llength [info commands "portindexhandle${i}"]] == 0} {
+				set cmdname "portindexhandle${i}"
+				break;
+			}
+		}
+
+		if {${cmdname} == ""} {
+			error "Couldn't find a free slot to create a new PortIndex handle.\
+				Make sure you don't have a resource leak."
+		}
+
+		# Create an alias and always pass the ${path} parameter
+		interp alias {} ${cmdname} {} portindex::handle_portindex_cmd ${type} ${path}
+		# Allow running initilization code
+		eval ${cmdname} open
+
+		return ${cmdname}
+	}
+
+	# Callback called for every command to be dispatched to a certain PortIndex
+	# handler. Makes sure the command is being run in the correct namespace.
+	# Also implements `$handle release`, which uses reference counting and only
+	# calls the corresponding PortIndex implementation command, if this was the
+	# last reference.
+	proc handle_portindex_cmd {type path cmd args} {
+		variable portindex_map
+		variable portindex_retain_count
+
+		if {${cmd} == "release"} {
+			incr portindex_retain_count($path) -1
+			if {[expr $portindex_retain_count($path) > 0]} {
+				# do nothing, the reference is still valid
+				return
+			}
+			# remove command, clear command maps, call destructor
+			set command $portindex_map($path)
+			unset portindex_map($path)
+			unset portindex_retain_count($path)
+			interp alias {} ${command} {}
+		}
+		return [namespace inscope ::portindex::${type} ${cmd} ${path} ${args}]
+	}
+
 	# Increase the number of ports in total. Call this once for every port
 	# processed from the portindex implementation
 	proc inc_total {{amount 1}} {

Modified: users/cal/base-sqlite-portindex/src/portindex1.0/sqlite.tcl
===================================================================
--- users/cal/base-sqlite-portindex/src/portindex1.0/sqlite.tcl	2013-02-24 23:11:50 UTC (rev 103406)
+++ users/cal/base-sqlite-portindex/src/portindex1.0/sqlite.tcl	2013-02-25 01:14:41 UTC (rev 103407)
@@ -34,6 +34,10 @@
 package provide portindex::sqlite 1.0
 
 namespace eval portindex::sqlite {
+    ########################
+    # PortIndex generation #
+    ########################
+
     # The output directory for the PortIndex
     variable outdir
 
@@ -565,7 +569,7 @@
         return [namespace code {pindex}]
     }
 
-    # Cleanup procedure called after portindex::replace.
+    # Cleanup procedure called at the end of portindex::update
     proc finish {} {
         variable db
 
@@ -574,4 +578,65 @@
         }
         db close
     }
+
+    #####################
+    # PortIndex reading #
+    #####################
+
+    # map from database names to paths
+    variable db_names
+    array set db_names {}
+
+    # map from paths to database names
+    variable dbs
+    array set dbs {}
+
+    # Checks whether a given path looks like a SQLite-indexed ports tree.
+    # Returns 1 if the given path seems to match, 0 otherwise. Never throws errors.
+    proc seems_like_valid_portindex {path} {
+        set database [file join ${path} PortIndex.db]
+
+        return [file exists ${database}]
+    }
+
+    # Open a new PortIndex. This will only be called if seems_like_valid_portindex returned 1, so
+    # assuming the checks done there came back true is possible.
+    proc open {path args} {
+        variable db_names
+        variable dbs
+
+        package require sqlite3
+
+        set database [file join ${path} PortIndex.db]
+
+        set dbname ""
+        for {set i 0} {$i < 1000} {incr i} {
+            if {[llength [info commands "portindexsqlitedb${i}"]] == 0} {
+                set dbname "portindexsqlitedb${i}"
+                break;
+            }
+        }
+        if {${dbname} == ""} {
+            error "Couldn't find a free slot to create a new database connection.\
+                Make sure you don't have a resource leak."
+        }
+
+        if {[catch {sqlite3 ${dbname} ${database}} result]} {
+            error "error opening database ${database}: ${result}"
+        }
+
+        set dbs($path) $dbname
+        set db_names($dbname) $path
+    }
+
+    # Close a PortIndex and release all resources associated with it.
+    proc release {path args} {
+        variable dbs
+        variable db_names
+
+        set dbname $dbs($path)
+        $dbs($path) close
+        unset dbs($path)
+        unset db_names($dbname)
+    }
 }
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20130224/db5de569/attachment-0001.html>


More information about the macports-changes mailing list