<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[117407] trunk/base</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="https://trac.macports.org/changeset/117407">117407</a></dd>
<dt>Author</dt> <dd>jmr@macports.org</dd>
<dt>Date</dt> <dd>2014-02-25 10:28:14 -0800 (Tue, 25 Feb 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>store portgroups in the registry, so they can always be used by the portfiles, especially when a portgroup only exists in a non-default source.
move portfiles out of the db and into the filesystem, and deduplicate them (for when the same version is installed with different variants)</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkbaseMakefilein">trunk/base/Makefile.in</a></li>
<li><a href="#trunkbaseportmgrdmgpostflight">trunk/base/portmgr/dmg/postflight</a></li>
<li><a href="#trunkbasesrccregistryMakefile">trunk/base/src/cregistry/Makefile</a></li>
<li><a href="#trunkbasesrccregistryentryc">trunk/base/src/cregistry/entry.c</a></li>
<li><a href="#trunkbasesrccregistryentryh">trunk/base/src/cregistry/entry.h</a></li>
<li><a href="#trunkbasesrccregistryregistryc">trunk/base/src/cregistry/registry.c</a></li>
<li><a href="#trunkbasesrccregistryregistryh">trunk/base/src/cregistry/registry.h</a></li>
<li><a href="#trunkbasesrccregistrysqlc">trunk/base/src/cregistry/sql.c</a></li>
<li><a href="#trunkbasesrcmacports10macportstcl">trunk/base/src/macports1.0/macports.tcl</a></li>
<li><a href="#trunkbasesrcmacports10testsmacportstest">trunk/base/src/macports1.0/tests/macports.test</a></li>
<li><a href="#trunkbasesrcpextlib10tracelibc">trunk/base/src/pextlib1.0/tracelib.c</a></li>
<li><a href="#trunkbasesrcport10portinstalltcl">trunk/base/src/port1.0/portinstall.tcl</a></li>
<li><a href="#trunkbasesrcport10portutiltcl">trunk/base/src/port1.0/portutil.tcl</a></li>
<li><a href="#trunkbasesrcregistry20Makefile">trunk/base/src/registry2.0/Makefile</a></li>
<li><a href="#trunkbasesrcregistry20entryobjc">trunk/base/src/registry2.0/entryobj.c</a></li>
<li><a href="#trunkbasesrcregistry20portuninstalltcl">trunk/base/src/registry2.0/portuninstall.tcl</a></li>
<li><a href="#trunkbasesrcregistry20registryc">trunk/base/src/registry2.0/registry.c</a></li>
<li><a href="#trunkbasesrcregistry20registryh">trunk/base/src/registry2.0/registry.h</a></li>
<li><a href="#trunkbasesrcregistry20registry_utiltcl">trunk/base/src/registry2.0/registry_util.tcl</a></li>
<li><a href="#trunkbasesrcregistry20utilc">trunk/base/src/registry2.0/util.c</a></li>
<li><a href="#trunkbasesrcregistry20utilh">trunk/base/src/registry2.0/util.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkbasesrccregistryportgroupc">trunk/base/src/cregistry/portgroup.c</a></li>
<li><a href="#trunkbasesrccregistryportgrouph">trunk/base/src/cregistry/portgroup.h</a></li>
<li><a href="#trunkbasesrcdedup_portfilestcl">trunk/base/src/dedup_portfiles.tcl</a></li>
<li><a href="#trunkbasesrcregistry20portgroupc">trunk/base/src/registry2.0/portgroup.c</a></li>
<li><a href="#trunkbasesrcregistry20portgrouph">trunk/base/src/registry2.0/portgroup.h</a></li>
<li><a href="#trunkbasesrcregistry20portgroupobjc">trunk/base/src/registry2.0/portgroupobj.c</a></li>
<li><a href="#trunkbasesrcregistry20portgroupobjh">trunk/base/src/registry2.0/portgroupobj.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkbaseMakefilein"></a>
<div class="modfile"><h4>Modified: trunk/base/Makefile.in (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/Makefile.in        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/Makefile.in        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -94,6 +94,7 @@
</span><span class="cx">         $(TCLSH) src/upgrade_sources_conf_default.tcl "${prefix}"
</span><span class="cx"> # Convert image directories (and direct mode installs) to image archives
</span><span class="cx">         $(TCLSH) src/images_to_archives.tcl "${macports_tcl_dir}"
</span><ins>+        $(TCLSH) src/dedup_portfiles.tcl "${macports_tcl_dir}"
</ins><span class="cx"> endif
</span><span class="cx"> ifndef SELFUPDATING
</span><span class="cx">         @echo ""; echo "Congratulations, you have successfully installed the MacPorts system. To get the Portfiles and update the system, add ${prefix}/bin to your PATH and run:"; echo ""
</span></span></pre></div>
<a id="trunkbaseportmgrdmgpostflight"></a>
<div class="modfile"><h4>Modified: trunk/base/portmgr/dmg/postflight (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/portmgr/dmg/postflight        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/portmgr/dmg/postflight        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -74,6 +74,7 @@
</span><span class="cx"> # Convert image directories (and direct mode installs) to image archives
</span><span class="cx"> echo "Updating port image format..."
</span><span class="cx"> ${TCLSH} ${SCRIPT_DIR}/images_to_archives.tcl ${MACPORTS_TCL_DIR}
</span><ins>+ ${TCLSH} ${SCRIPT_DIR}/dedup_portfiles.tcl ${MACPORTS_TCL_DIR}
</ins><span class="cx">
</span><span class="cx"> echo "Synchronizing the MacPorts installation with the project's rsync server..."
</span><span class="cx"> if ! ${BINPATH}/port -v selfupdate; then
</span></span></pre></div>
<a id="trunkbasesrccregistryMakefile"></a>
<div class="modfile"><h4>Modified: trunk/base/src/cregistry/Makefile (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/Makefile        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/cregistry/Makefile        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> # $Id$
</span><span class="cx">
</span><del>-OBJS = registry.o entry.o sql.o vercomp.o util.o file.o
</del><ins>+OBJS = registry.o entry.o sql.o vercomp.o util.o file.o portgroup.o
</ins><span class="cx"> STLIB_NAME = cregistry.a
</span><span class="cx"> RANLIB = ranlib
</span><span class="cx">
</span></span></pre></div>
<a id="trunkbasesrccregistryentryc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/cregistry/entry.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/entry.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/cregistry/entry.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -2,7 +2,7 @@
</span><span class="cx"> * entry.c
</span><span class="cx"> * $Id$
</span><span class="cx"> *
</span><del>- * Copyright (c) 2010-2011 The MacPorts Project
</del><ins>+ * Copyright (c) 2010-2011, 2014 The MacPorts Project
</ins><span class="cx"> * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
</span><span class="cx"> * All rights reserved.
</span><span class="cx"> *
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include <config.h>
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+#include "portgroup.h"
</ins><span class="cx"> #include "entry.h"
</span><span class="cx"> #include "registry.h"
</span><span class="cx"> #include "sql.h"
</span><span class="lines">@@ -246,9 +247,11 @@
</span><span class="cx"> sqlite3_stmt* ports = NULL;
</span><span class="cx"> sqlite3_stmt* files = NULL;
</span><span class="cx"> sqlite3_stmt* dependencies = NULL;
</span><ins>+ sqlite3_stmt* portgroups = NULL;
</ins><span class="cx"> char* ports_query = "DELETE FROM registry.ports WHERE id=?";
</span><span class="cx"> char* files_query = "DELETE FROM registry.files WHERE id=?";
</span><span class="cx"> char* dependencies_query = "DELETE FROM registry.dependencies WHERE id=?";
</span><ins>+ char* portgroups_query = "DELETE FROM registry.portgroups WHERE id=?";
</ins><span class="cx"> if ((sqlite3_prepare_v2(reg->db, ports_query, -1, &ports, NULL) == SQLITE_OK)
</span><span class="cx"> && (sqlite3_bind_int64(ports, 1, entry->id) == SQLITE_OK)
</span><span class="cx"> && (sqlite3_prepare_v2(reg->db, files_query, -1, &files, NULL)
</span><span class="lines">@@ -256,7 +259,10 @@
</span><span class="cx"> && (sqlite3_bind_int64(files, 1, entry->id) == SQLITE_OK)
</span><span class="cx"> && (sqlite3_prepare_v2(reg->db, dependencies_query, -1, &dependencies,
</span><span class="cx"> NULL) == SQLITE_OK)
</span><del>- && (sqlite3_bind_int64(dependencies, 1, entry->id) == SQLITE_OK)) {
</del><ins>+ && (sqlite3_bind_int64(dependencies, 1, entry->id) == SQLITE_OK)
+ && (sqlite3_prepare_v2(reg->db, portgroups_query, -1, &portgroups,
+ NULL) == SQLITE_OK)
+ && (sqlite3_bind_int64(portgroups, 1, entry->id) == SQLITE_OK)) {
</ins><span class="cx"> int r;
</span><span class="cx"> do {
</span><span class="cx"> r = sqlite3_step(ports);
</span><span class="lines">@@ -271,7 +277,20 @@
</span><span class="cx"> r = sqlite3_step(dependencies);
</span><span class="cx"> switch (r) {
</span><span class="cx"> case SQLITE_DONE:
</span><del>- result = 1;
</del><ins>+ do {
+ r = sqlite3_step(portgroups);
+ switch (r) {
+ case SQLITE_DONE:
+ result = 1;
+ break;
+ case SQLITE_BUSY:
+ break;
+ case SQLITE_ERROR:
+ reg_sqlite_error(reg->db,
+ errPtr, NULL);
+ break;
+ }
+ } while (r == SQLITE_BUSY);
</ins><span class="cx"> break;
</span><span class="cx"> case SQLITE_BUSY:
</span><span class="cx"> break;
</span><span class="lines">@@ -315,6 +334,9 @@
</span><span class="cx"> if (dependencies) {
</span><span class="cx"> sqlite3_finalize(dependencies);
</span><span class="cx"> }
</span><ins>+ if (portgroups) {
+ sqlite3_finalize(portgroups);
+ }
</ins><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -670,6 +692,73 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * Associates a portgroup with given port.
+ *
+ * @param [in] entry the entry to map the portgroup to
+ * @param [in] name the portgroup name (e.g. "muniversal")
+ * @param [in] version the portgroup version (e.g. "1.0")
+ * @param [in] sha256 the sha256 hash of the portgroup file
+ * @param [in] size the size of the portgroup file in bytes
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_entry_addgroup(reg_entry* entry, char* name, char *version,
+ char *sha256, sqlite_int64 size, reg_error* errPtr) {
+ reg_registry* reg = entry->reg;
+ int result = 1;
+ sqlite3_stmt* stmt = NULL;
+ char* insert = "INSERT INTO registry.portgroups (id, name, version, size, sha256) "
+ "VALUES (?, ?, ?, ?, ?)";
+ if ((sqlite3_prepare_v2(reg->db, insert, -1, &stmt, NULL) == SQLITE_OK)
+ && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 2, name, -1, SQLITE_STATIC) == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 3, version, -1, SQLITE_STATIC) == SQLITE_OK)
+ && (sqlite3_bind_int64(stmt, 4, size) == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 5, sha256, -1, SQLITE_STATIC) == SQLITE_OK)) {
+ int r;
+ do {
+ r = sqlite3_step(stmt);
+ switch (r) {
+ case SQLITE_DONE:
+ sqlite3_reset(stmt);
+ break;
+ case SQLITE_BUSY:
+ break;
+ default:
+ reg_sqlite_error(reg->db, errPtr, insert);
+ result = 0;
+ break;
+ }
+ } while (r == SQLITE_BUSY);
+ } else {
+ reg_sqlite_error(reg->db, errPtr, insert);
+ result = 0;
+ }
+ if (stmt) {
+ sqlite3_finalize(stmt);
+ }
+ return result;
+}
+
+/**
+ * Gets a list of portgroups that are used by this port.
+ *
+ * @param [in] entry a port
+ * @param [out] portgroups a list of portgroups used by the given port
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_entry_getgroups(reg_entry* entry, reg_portgroup*** portgroups, reg_error* errPtr) {
+ reg_registry* reg = entry->reg;
+ char* query = sqlite3_mprintf("SELECT ROWID FROM portgroups "
+ "WHERE id=%lld",
+ entry->id);
+ int result = reg_all_portgroups(reg, query, -1, portgroups, errPtr);
+ sqlite3_free(query);
+ return result;
+}
+
+/**
</ins><span class="cx"> * Maps files to the given port in the filemap. The list of files must not
</span><span class="cx"> * contain files that are already mapped to the given port.
</span><span class="cx"> *
</span></span></pre></div>
<a id="trunkbasesrccregistryentryh"></a>
<div class="modfile"><h4>Modified: trunk/base/src/cregistry/entry.h (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/entry.h        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/cregistry/entry.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -71,6 +71,11 @@
</span><span class="cx"> int reg_entry_propset(reg_entry* entry, char* key, char* value,
</span><span class="cx"> reg_error* errPtr);
</span><span class="cx">
</span><ins>+int reg_entry_addgroup(reg_entry* entry, char* name, char *version,
+ char *sha256, sqlite_int64 size, reg_error* errPtr);
+int reg_entry_getgroups(reg_entry* entry, reg_portgroup*** portgroups,
+ reg_error* errPtr);
+
</ins><span class="cx"> int reg_entry_map(reg_entry* entry, char** files, int file_count,
</span><span class="cx"> reg_error* errPtr);
</span><span class="cx"> int reg_entry_unmap(reg_entry* entry, char** files, int file_count,
</span></span></pre></div>
<a id="trunkbasesrccregistryportgroupc"></a>
<div class="addfile"><h4>Added: trunk/base/src/cregistry/portgroup.c (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/portgroup.c         (rev 0)
+++ trunk/base/src/cregistry/portgroup.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,318 @@
</span><ins>+/*
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "portgroup.h"
+#include "util.h"
+#include "registry.h"
+#include "sql.h"
+
+#include <sqlite3.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Converts a `sqlite3_stmt` into a `reg_portgroup`. The first column of the stmt's
+ * row must be the id of a portgroup; the second either `SQLITE_NULL` or the
+ * address of the entry in memory.
+ *
+ * @param [in] userdata sqlite3 database
+ * @param [out] portgroup portgroup described by `stmt`
+ * @param [in] stmt `sqlite3_stmt` with appropriate columns
+ * @param [out] errPtr unused
+ * @return true if success; false if failure
+ */
+static int reg_stmt_to_portgroup(void* userdata, void** portgroup, void* stmt,
+ void* calldata UNUSED, reg_error* errPtr UNUSED) {
+ int is_new;
+ reg_registry* reg = (reg_registry*)userdata;
+ sqlite_int64 id = sqlite3_column_int64(stmt, 0);
+ Tcl_HashEntry* hash = Tcl_CreateHashEntry(&reg->open_portgroups,
+ (const char*)&id, &is_new);
+ if (is_new) {
+ reg_portgroup* p = malloc(sizeof(reg_portgroup));
+ if (!p) {
+ return 0;
+ }
+ p->reg = reg;
+ p->id = id;
+ p->proc = NULL;
+ *portgroup = p;
+ Tcl_SetHashValue(hash, p);
+ } else {
+ *portgroup = Tcl_GetHashValue(hash);
+ }
+ return 1;
+}
+
+/**
+ * Type-safe version of `reg_all_objects` for `reg_portgroup`.
+ *
+ * @param [in] reg registry to select entries from
+ * @param [in] query the select query to execute
+ * @param [in] query_len length of the query (or -1 for automatic)
+ * @param [out] objects the portgroups selected
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return the number of entries if success; negative if failure
+ */
+int reg_all_portgroups(reg_registry* reg, char* query, int query_len,
+ reg_portgroup*** objects, reg_error* errPtr) {
+ int lower_bound = 0;
+ return reg_all_objects(reg, query, query_len, (void***)objects,
+ reg_stmt_to_portgroup, &lower_bound, NULL, errPtr);
+}
+
+/**
+ * Searches the registry for portgroups for which each key's value is equal to the
+ * given value. To find all portgroups, pass a key_count of 0.
+ *
+ * Bad keys should cause sqlite3 errors but not permit SQL injection attacks.
+ * Pass it good keys anyway.
+ *
+ * @param [in] reg registry to search in
+ * @param [in] keys a list of keys to search by
+ * @param [in] vals a list of values to search by, matching keys
+ * @param [in] strats a list of strategies to use when searching
+ * @param [in] key_count the number of key/value pairs passed
+ * @param [out] portgroups a list of matching portgroups
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return the number of entries if success; false if failure
+ */
+int reg_portgroup_search(reg_registry* reg, char** keys, char** vals, int* strats,
+ int key_count, reg_portgroup*** portgroups, reg_error* errPtr) {
+ int i;
+ char* kwd = " WHERE ";
+ char* query;
+ size_t query_len, query_space;
+ int result;
+
+ /* build the query */
+ query = strdup("SELECT ROWID FROM registry.portgroups");
+ if (!query) {
+ return -1;
+ }
+ query_len = query_space = strlen(query);
+
+ for (i = 0; i < key_count; i++) {
+ char* op;
+ char* cond;
+
+ /* get the strategy */
+ if ((op = reg_strategy_op(strats[i], errPtr)) == NULL) {
+ free(query);
+ return -1;
+ }
+
+ cond = sqlite3_mprintf(op, keys[i], vals[i]);
+ if (!cond || !reg_strcat(&query, &query_len, &query_space, kwd)
+ || !reg_strcat(&query, &query_len, &query_space, cond)) {
+ free(query);
+ return -1;
+ }
+ sqlite3_free(cond);
+ kwd = " AND ";
+ }
+
+ /* do the query */
+ result = reg_all_portgroups(reg, query, -1, portgroups, errPtr);
+ free(query);
+ return result;
+}
+
+/**
+ * Gets a named property of a portgroup. That property can be set using
+ * `reg_portgroup_propset`. The property named must be one that exists in the table
+ * and must not be one with internal meaning such as `id` or `state`.
+ *
+ * @param [in] portgroup portgroup to get property from
+ * @param [in] key property to get
+ * @param [out] value the value of the property
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_portgroup_propget(reg_portgroup* portgroup, char* key, char** value,
+ reg_error* errPtr) {
+ reg_registry* reg = portgroup->reg;
+ int result = 0;
+ sqlite3_stmt* stmt = NULL;
+ char* query;
+ const char *text;
+ query = sqlite3_mprintf("SELECT %q FROM registry.portgroups WHERE ROWID=%lld", key,
+ portgroup->id);
+ if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
+ int r;
+ do {
+ r = sqlite3_step(stmt);
+ switch (r) {
+ case SQLITE_ROW:
+ text = (const char*)sqlite3_column_text(stmt, 0);
+ if (text) {
+ *value = strdup(text);
+ result = 1;
+ } else {
+ reg_sqlite_error(reg->db, errPtr, query);
+ }
+ break;
+ case SQLITE_DONE:
+ errPtr->code = REG_INVALID;
+ errPtr->description = "an invalid portgroup was passed";
+ errPtr->free = NULL;
+ break;
+ case SQLITE_BUSY:
+ continue;
+ default:
+ reg_sqlite_error(reg->db, errPtr, query);
+ break;
+ }
+ } while (r == SQLITE_BUSY);
+ } else {
+ reg_sqlite_error(reg->db, errPtr, query);
+ }
+ if (stmt) {
+ sqlite3_finalize(stmt);
+ }
+ sqlite3_free(query);
+ return result;
+}
+
+/**
+ * Sets a named property of an portgroup. That property can be later retrieved using
+ * `reg_portgroup_propget`. The property named must be one that exists in the table
+ * and must not be one with internal meaning such as `id` or `state`. If `name`,
+ * `epoch`, `version`, `revision`, or `variants` is set, it could trigger a
+ * conflict if another port with the same combination of values for those
+ * columns exists.
+ *
+ * @param [in] portgroup portgroup to set property for
+ * @param [in] key property to set
+ * @param [in] value the desired value of the property
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return true if success; false if failure
+ */
+int reg_portgroup_propset(reg_portgroup* portgroup, char* key, char* value,
+ reg_error* errPtr) {
+ reg_registry* reg = portgroup->reg;
+ int result = 0;
+ sqlite3_stmt* stmt = NULL;
+ char* query;
+ query = sqlite3_mprintf("UPDATE registry.ports SET %q = '%q' WHERE ROWID=%lld",
+ key, value, portgroup->id);
+ if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
+ int r;
+ do {
+ r = sqlite3_step(stmt);
+ switch (r) {
+ case SQLITE_DONE:
+ result = 1;
+ break;
+ case SQLITE_BUSY:
+ break;
+ default:
+ if (sqlite3_reset(stmt) == SQLITE_CONSTRAINT) {
+ errPtr->code = REG_CONSTRAINT;
+ errPtr->description = "a constraint was disobeyed";
+ errPtr->free = NULL;
+ } else {
+ reg_sqlite_error(reg->db, errPtr, query);
+ }
+ break;
+ }
+ } while (r == SQLITE_BUSY);
+ } else {
+ reg_sqlite_error(reg->db, errPtr, query);
+ }
+ if (stmt) {
+ sqlite3_finalize(stmt);
+ }
+ sqlite3_free(query);
+ return result;
+}
+
+/**
+ * Opens an existing portgroup in the registry.
+ *
+ * @param [in] reg registry to open portgroup in
+ * @param [in] id id of entry referencing portgroup
+ * @param [in] name name of portgroup
+ * @param [in] version version of portgroup
+ * @param [in] size size of portgroup
+ * @param [in] sha256 sha256 of portgroup
+ * @param [out] errPtr on error, a description of the error that occurred
+ * @return the portgroup if success; NULL if failure
+ */
+reg_portgroup* reg_portgroup_open(reg_registry* reg, char *id, char* name, char* version,
+ char* size, char* sha256, reg_error* errPtr) {
+ sqlite3_stmt* stmt = NULL;
+ reg_portgroup* portgroup = NULL;
+ int lower_bound = 0;
+ char* query;
+ query = "SELECT ROWID FROM registry.portgroups WHERE id=? AND name=? AND version=? "
+ "AND size=? AND sha256=?";
+ if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 1, id, -1, SQLITE_STATIC)
+ == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 2, name, -1, SQLITE_STATIC)
+ == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 3, version, -1, SQLITE_STATIC)
+ == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 4, size, -1, SQLITE_STATIC)
+ == SQLITE_OK)
+ && (sqlite3_bind_text(stmt, 5, sha256, -1, SQLITE_STATIC)
+ == SQLITE_OK)) {
+ int r;
+ do {
+ r = sqlite3_step(stmt);
+ switch (r) {
+ case SQLITE_ROW:
+ reg_stmt_to_portgroup(reg, (void**)&portgroup, stmt, &lower_bound, errPtr);
+ break;
+ case SQLITE_DONE:
+ errPtr->code = REG_NOT_FOUND;
+ errPtr->description = sqlite3_mprintf("no matching portgroup found for: " \
+ "id=%s, name=%s, version=%s, size=%s, sha256=%s", \
+ id, name, version, size, sha256);
+ errPtr->free = (reg_error_destructor*) sqlite3_free;
+ break;
+ case SQLITE_BUSY:
+ continue;
+ default:
+ reg_sqlite_error(reg->db, errPtr, query);
+ break;
+ }
+ } while (r == SQLITE_BUSY);
+ } else {
+ reg_sqlite_error(reg->db, errPtr, query);
+ }
+ if (stmt) {
+ sqlite3_finalize(stmt);
+ }
+ return portgroup;
+}
</ins></span></pre></div>
<a id="trunkbasesrccregistryportgrouph"></a>
<div class="addfile"><h4>Added: trunk/base/src/cregistry/portgroup.h (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/portgroup.h         (rev 0)
+++ trunk/base/src/cregistry/portgroup.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+/*
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _CPORTGROUP_H
+#define _CPORTGROUP_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "registry.h"
+
+#include <sqlite3.h>
+
+typedef struct {
+ sqlite_int64 id; /* rowid in the database */
+ reg_registry* reg; /* associated registry */
+ char* proc; /* name of Tcl proc, if using Tcl */
+} reg_portgroup;
+
+int reg_portgroup_search(reg_registry* reg, char** keys, char** vals, int* strats,
+ int key_count, reg_portgroup*** portgroups, reg_error* errPtr);
+int reg_all_portgroups(reg_registry* reg, char* query, int query_len,
+ reg_portgroup*** objects, reg_error* errPtr);
+reg_portgroup* reg_portgroup_open(reg_registry* reg, char *id, char* name, char* version,
+ char* size, char* sha256, reg_error* errPtr);
+int reg_portgroup_propget(reg_portgroup* portgroup, char* key, char** value,
+ reg_error* errPtr);
+int reg_portgroup_propset(reg_portgroup* portgroup, char* key, char* value,
+ reg_error* errPtr);
+
+#endif /* _CPORTGROUP_H */
</ins></span></pre></div>
<a id="trunkbasesrccregistryregistryc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/cregistry/registry.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/registry.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/cregistry/registry.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -4,7 +4,7 @@
</span><span class="cx"> * vim:expandtab:tw=80
</span><span class="cx"> *
</span><span class="cx"> * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
</span><del>- * Copyright (c) 2012 The MacPorts Project
</del><ins>+ * Copyright (c) 2012, 2014 The MacPorts Project
</ins><span class="cx"> * All rights reserved.
</span><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> #include <config.h>
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+#include "portgroup.h"
</ins><span class="cx"> #include "entry.h"
</span><span class="cx"> #include "file.h"
</span><span class="cx"> #include "sql.h"
</span><span class="lines">@@ -208,6 +209,8 @@
</span><span class="cx"> sizeof(sqlite_int64)/sizeof(int));
</span><span class="cx"> Tcl_InitHashTable(&reg->open_files,
</span><span class="cx"> TCL_STRING_KEYS);
</span><ins>+ Tcl_InitHashTable(&reg->open_portgroups,
+ sizeof(sqlite_int64)/sizeof(int));
</ins><span class="cx"> reg->status |= reg_attached;
</span><span class="cx"> result = 1;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkbasesrccregistryregistryh"></a>
<div class="modfile"><h4>Modified: trunk/base/src/cregistry/registry.h (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/registry.h        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/cregistry/registry.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -4,7 +4,7 @@
</span><span class="cx"> * $Id$
</span><span class="cx"> *
</span><span class="cx"> * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
</span><del>- * Copyright (c) 2012 The MacPorts Project
</del><ins>+ * Copyright (c) 2012, 2014 The MacPorts Project
</ins><span class="cx"> * All rights reserved.
</span><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -73,6 +73,7 @@
</span><span class="cx"> int status;
</span><span class="cx"> Tcl_HashTable open_entries;
</span><span class="cx"> Tcl_HashTable open_files;
</span><ins>+ Tcl_HashTable open_portgroups;
</ins><span class="cx"> } reg_registry;
</span><span class="cx">
</span><span class="cx"> int reg_open(reg_registry** regPtr, reg_error* errPtr);
</span></span></pre></div>
<a id="trunkbasesrccregistrysqlc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/cregistry/sql.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/cregistry/sql.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/cregistry/sql.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> * $Id$
</span><span class="cx"> *
</span><span class="cx"> * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
</span><del>- * Copyright (c) 2012 The MacPorts Project
</del><ins>+ * Copyright (c) 2012, 2014 The MacPorts Project
</ins><span class="cx"> * All rights reserved.
</span><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -129,13 +129,13 @@
</span><span class="cx">
</span><span class="cx"> /* metadata table */
</span><span class="cx"> "CREATE TABLE registry.metadata (key UNIQUE, value)",
</span><del>- "INSERT INTO registry.metadata (key, value) VALUES ('version', 1.100)",
</del><ins>+ "INSERT INTO registry.metadata (key, value) VALUES ('version', 1.200)",
</ins><span class="cx"> "INSERT INTO registry.metadata (key, value) VALUES ('created', strftime('%s', 'now'))",
</span><span class="cx">
</span><span class="cx"> /* ports table */
</span><span class="cx"> "CREATE TABLE registry.ports ("
</span><del>- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "name TEXT COLLATE NOCASE, portfile CLOB, url TEXT, "
</del><ins>+ "id INTEGER PRIMARY KEY, "
+ "name TEXT COLLATE NOCASE, portfile TEXT, url TEXT, "
</ins><span class="cx"> "location TEXT, epoch INTEGER, version TEXT COLLATE VERSION, "
</span><span class="cx"> "revision INTEGER, variants TEXT, negated_variants TEXT, "
</span><span class="cx"> "state TEXT, date DATETIME, installtype TEXT, archs TEXT, "
</span><span class="lines">@@ -163,6 +163,11 @@
</span><span class="cx"> "FOREIGN KEY(id) REFERENCES ports(id))",
</span><span class="cx"> "CREATE INDEX registry.dep_name ON dependencies (name)",
</span><span class="cx">
</span><ins>+ /* portgroups table */
+ "CREATE TABLE registry.portgroups (id INTEGER, "
+ "name TEXT, version TEXT COLLATE VERSION, size INTEGER, sha256 TEXT, "
+ "FOREIGN KEY(id) REFERENCES ports(id))",
+
</ins><span class="cx"> "COMMIT",
</span><span class="cx"> NULL
</span><span class="cx"> };
</span><span class="lines">@@ -321,6 +326,36 @@
</span><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (sql_version(NULL, -1, version, -1, "1.2") < 0) {
+ /* We need to add the portgroup table and move the portfiles out
+ of the db and into the filesystem. The latter is way easier to do
+ from Tcl, so here we'll just flag that it needs to be done. */
+ static char* version_1_2_queries[] = {
+ /* portgroups table */
+ "CREATE TABLE registry.portgroups (id INTEGER, "
+ "name TEXT, version TEXT COLLATE VERSION, size INTEGER, sha256 TEXT, "
+ "FOREIGN KEY(id) REFERENCES ports(id))",
+
+ "UPDATE registry.metadata SET value = '1.200' WHERE key = 'version'",
+
+ "INSERT INTO registry.metadata (key, value) VALUES ('portfiles_update_needed', 1)",
+
+ "COMMIT",
+ NULL
+ };
+
+ sqlite3_finalize(stmt);
+ stmt = NULL;
+
+ if (!do_queries(db, version_1_2_queries, errPtr)) {
+ rollback_db(db);
+ return 0;
+ }
+
+ did_update = 1;
+ continue;
+ }
+
</ins><span class="cx"> /* add new versions here, but remember to:
</span><span class="cx"> * - finalize the version query statement and set stmt to NULL
</span><span class="cx"> * - do _not_ use "BEGIN" in your query list, since a transaction has
</span></span></pre></div>
<a id="trunkbasesrcdedup_portfilestcl"></a>
<div class="addfile"><h4>Added: trunk/base/src/dedup_portfiles.tcl (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/dedup_portfiles.tcl         (rev 0)
+++ trunk/base/src/dedup_portfiles.tcl        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+#!/usr/bin/env tclsh
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
+# $Id$
+
+# move portfiles from sqlite db to filesystem, while deduplicating
+# Takes one argument, which should be TCL_PACKAGE_DIR.
+
+source [file join [lindex $argv 0] macports1.0 macports_fastload.tcl]
+package require macports 1.0
+package require registry2 2.0
+package require Pextlib 1.0
+
+umask 022
+
+array set ui_options {ports_verbose yes}
+
+mportinit ui_options
+
+if {[registry::metadata get portfiles_update_needed] == 1} {
+ set portfiles_dir [file join ${macports::registry.path} registry portfiles]
+
+ registry::write {
+ set installed_ports [registry::entry imaged]
+ foreach portref $installed_ports {
+ set portfile_contents [$portref portfile]
+ if {$portfile_contents ne "" && $portfile_contents ne "0"} {
+ set portfile_partial_dir [file join $portfiles_dir [$portref name]-[$portref version]_[$portref revision]]
+ file mkdir $portfile_partial_dir
+ set portfile_temp_path ${portfile_partial_dir}/Portfile
+ set fd [open $portfile_temp_path w]
+ puts $fd $portfile_contents
+ close $fd
+
+ set hash_size [sha256 file $portfile_temp_path]-[file size $portfile_temp_path]
+ set portfile_dir [file join $portfile_partial_dir $hash_size]
+ file mkdir $portfile_dir
+ file rename -force $portfile_temp_path $portfile_dir
+ file mtime ${portfile_dir}/Portfile [$portref date]
+
+ $portref portfile $hash_size
+ }
+ }
+ registry::metadata del portfiles_update_needed
+ }
+}
+
+exit 0
</ins><span class="cx">Property changes on: trunk/base/src/dedup_portfiles.tcl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="svnkeywords"></a>
<div class="addfile"><h4>Added: svn:keywords</h4></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<a id="trunkbasesrcmacports10macportstcl"></a>
<div class="modfile"><h4>Modified: trunk/base/src/macports1.0/macports.tcl (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/macports1.0/macports.tcl        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/macports1.0/macports.tcl        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -1363,12 +1363,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> foreach {opt val} $options {
</span><del>- $workername eval set user_options($opt) $val
- $workername eval set $opt $val
</del><ins>+ $workername eval [list set user_options($opt) $val]
+ $workername eval [list set $opt $val]
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> foreach {var val} $variations {
</span><del>- $workername eval set variations($var) $val
</del><ins>+ $workername eval [list set variations($var) $val]
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1715,12 +1715,7 @@
</span><span class="cx"> proc mportopen_installed {name version revision variants options} {
</span><span class="cx"> global macports::registry.path
</span><span class="cx"> set regref [lindex [registry::entry imaged $name $version $revision $variants] 0]
</span><del>- set portfile_dir [file join ${registry.path} registry portfiles $name ${version}_${revision}$variants]
- file mkdir $portfile_dir
- set fd [open ${portfile_dir}/Portfile w]
- puts $fd [$regref portfile]
- close $fd
- file mtime ${portfile_dir}/Portfile [$regref date]
</del><ins>+ set portfile_dir [file join ${registry.path} registry portfiles ${name}-${version}_${revision} [$regref portfile]]
</ins><span class="cx">
</span><span class="cx"> set variations {}
</span><span class="cx"> set minusvariant [lrange [split [$regref negated_variants] -] 1 end]
</span><span class="lines">@@ -1732,23 +1727,17 @@
</span><span class="cx"> lappend variations $v -
</span><span class="cx"> }
</span><span class="cx"> lappend options subport $name
</span><del>- return [mportopen file://${portfile_dir}/ $options $variations]
-}
</del><span class="cx">
</span><del>-# mportclose_installed
-# close mport opened with mportopen_installed and clean up associated files
-proc mportclose_installed {mport} {
- global macports::registry.path
- foreach key {subport version revision portvariants} {
- set $key [_mportkey $mport $key]
</del><ins>+ # find portgroups in registry
+ set pgdirlist [list]
+ foreach pg [$regref groups_used] {
+ lappend pgdirlist [file join ${registry.path} registry portgroups [$pg sha256]-[$pg size]]
</ins><span class="cx"> }
</span><del>- mportclose $mport
- set portfiles_dir [file join ${registry.path} registry portfiles $subport]
- set portfile [file join $portfiles_dir ${version}_${revision}$portvariants Portfile]
- file delete -force $portfile [file dirname $portfile]
- if {[llength [glob -nocomplain -directory $portfiles_dir *]] == 0} {
- file delete -force $portfiles_dir
</del><ins>+ if {$pgdirlist ne {}} {
+ lappend options _portgroup_search_dirs $pgdirlist
</ins><span class="cx"> }
</span><ins>+
+ return [mportopen file://${portfile_dir}/ $options $variations]
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> # Traverse a directory with ports, calling a function on the path of ports
</span></span></pre></div>
<a id="trunkbasesrcmacports10testsmacportstest"></a>
<div class="modfile"><h4>Modified: trunk/base/src/macports1.0/tests/macports.test (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/macports1.0/tests/macports.test        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/macports1.0/tests/macports.test        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -153,10 +153,10 @@
</span><span class="cx"> return "FAIL: installed port not opened"
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if {[catch {mportclose_installed $res}] != 0} {
</del><ins>+ if {[catch {mportclose $res}] != 0} {
</ins><span class="cx"> return "FAIL: cannot close port"
</span><span class="cx"> }
</span><del>- if {[catch {mportclose_installed $res}] != 1} {
</del><ins>+ if {[catch {mportclose $res}] != 1} {
</ins><span class="cx"> return "FAIL: installed port not closed"
</span><span class="cx"> }
</span><span class="cx"> return "Installed port open successful."
</span><span class="lines">@@ -702,10 +702,6 @@
</span><span class="cx"> # test mportopen
</span><span class="cx">
</span><span class="cx">
</span><del>-# Covered by mportopen_installed
-# test mportclose_installed
-
-
</del><span class="cx"> test mporttraverse {
</span><span class="cx"> Mport traverse unit test. Uses 3rd column of the Portfile.
</span><span class="cx"> } -setup {
</span></span></pre></div>
<a id="trunkbasesrcpextlib10tracelibc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/pextlib1.0/tracelib.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/pextlib1.0/tracelib.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/pextlib1.0/tracelib.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -56,6 +56,7 @@
</span><span class="cx"> #include <sys/un.h>
</span><span class="cx"> #include <unistd.h>
</span><span class="cx">
</span><ins>+#include <cregistry/portgroup.h>
</ins><span class="cx"> #include <cregistry/entry.h>
</span><span class="cx"> #include <registry2.0/registry.h>
</span><span class="cx">
</span></span></pre></div>
<a id="trunkbasesrcport10portinstalltcl"></a>
<div class="modfile"><h4>Modified: trunk/base/src/port1.0/portinstall.tcl (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/port1.0/portinstall.tcl        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/port1.0/portinstall.tcl        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -307,7 +307,7 @@
</span><span class="cx"> homepage depends_run package-install workdir workpath \
</span><span class="cx"> worksrcdir UI_PREFIX destroot revision maintainers user_options \
</span><span class="cx"> portvariants negated_variants targets depends_lib PortInfo epoch license \
</span><del>- os.platform os.major portarchivetype installPlist
</del><ins>+ os.platform os.major portarchivetype installPlist registry.path porturl
</ins><span class="cx">
</span><span class="cx"> set oldpwd [pwd]
</span><span class="cx"> if {$oldpwd eq ""} {
</span><span class="lines">@@ -373,11 +373,40 @@
</span><span class="cx"> # register files
</span><span class="cx"> $regref map $installPlist
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> # store portfile
</span><del>- set fd [open [file join ${portpath} Portfile]]
- $regref portfile [read $fd]
- close $fd
</del><ins>+ set portfile_path [file join $portpath Portfile]
+ set portfile_sha256 [sha256 file $portfile_path]
+ set portfile_size [file size $portfile_path]
+ set portfile_reg_dir [file join ${registry.path} registry portfiles ${subport}-${version}_${revision} ${portfile_sha256}-${portfile_size}]
+ file mkdir $portfile_reg_dir
+ set portfile_reg_path ${portfile_reg_dir}/Portfile
+ if {![file isfile $portfile_reg_path] || [file size $portfile_reg_path] != $portfile_size || [sha256 file $portfile_reg_path] ne $portfile_sha256} {
+ file copy -force $portfile_path $portfile_reg_dir
+ }
+ $regref portfile ${portfile_sha256}-${portfile_size}
+
+ # store portgroups
+ if {[info exists PortInfo(portgroups)]} {
+ foreach pg $PortInfo(portgroups) {
+ set pgname [lindex $pg 0]
+ set pgversion [lindex $pg 1]
+ set groupFile [getportresourcepath $porturl "port1.0/group/${pgname}-${pgversion}.tcl"]
+ if {[file isfile $groupFile]} {
+ set pgsha256 [sha256 file $groupFile]
+ set pgsize [file size $groupFile]
+ set pg_reg_dir [file join ${registry.path} registry portgroups ${pgsha256}-${pgsize}]
+ set pg_reg_path ${pg_reg_dir}/${pgname}-${pgversion}.tcl
+ if {![file isfile $pg_reg_path] || [file size $pg_reg_path] != $pgsize || [sha256 file $pg_reg_path] ne $pgsha256} {
+ file mkdir $pg_reg_dir
+ file copy -force $groupFile $pg_reg_dir
+ }
+ $regref addgroup $pgname $pgversion $pgsha256 $pgsize
+ } else {
+ ui_debug "install_main: no portgroup ${pgname}-${pgversion}.tcl found"
+ }
+ }
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> _cd $oldpwd
</span></span></pre></div>
<a id="trunkbasesrcport10portutiltcl"></a>
<div class="modfile"><h4>Modified: trunk/base/src/port1.0/portutil.tcl (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/port1.0/portutil.tcl        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/port1.0/portutil.tcl        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -2569,12 +2569,12 @@
</span><span class="cx">
</span><span class="cx"> # Use a specified group/version.
</span><span class="cx"> proc PortGroup {group version} {
</span><del>- global porturl PortInfo
</del><ins>+ global porturl PortInfo _portgroup_search_dirs
</ins><span class="cx">
</span><span class="cx"> lappend PortInfo(portgroups) [list $group $version]
</span><span class="cx">
</span><del>- if {[info exists portutil::portgroup_search_dirs]} {
- foreach dir $portutil::portgroup_search_dirs {
</del><ins>+ if {[info exists _portgroup_search_dirs]} {
+ foreach dir $_portgroup_search_dirs {
</ins><span class="cx"> set groupFile ${dir}/${group}-${version}.tcl
</span><span class="cx"> if {[file exists $groupFile]} {
</span><span class="cx"> uplevel "source $groupFile"
</span></span></pre></div>
<a id="trunkbasesrcregistry20Makefile"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/Makefile (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/Makefile        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/Makefile        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -3,7 +3,8 @@
</span><span class="cx"> SRCS = registry.tcl registry_autoconf.tcl registry_util.tcl receipt_flat.tcl receipt_sqlite.tcl portimage.tcl portuninstall.tcl
</span><span class="cx"> OBJS = registry.o util.o \
</span><span class="cx">         entry.o entryobj.o \
</span><del>-        file.o fileobj.o
</del><ins>+        file.o fileobj.o \
+        portgroup.o portgroupobj.o
</ins><span class="cx">         #graph.o graphobj.o
</span><span class="cx">
</span><span class="cx"> SHLIB_NAME= registry${SHLIB_SUFFIX}
</span></span></pre></div>
<a id="trunkbasesrcregistry20entryobjc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/entryobj.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/entryobj.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/entryobj.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -356,6 +356,59 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static int entry_obj_add_portgroup(Tcl_Interp* interp, reg_entry* entry, int objc,
+ Tcl_Obj* CONST objv[]) {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (objc != 6) {
+ Tcl_WrongNumArgs(interp, 1, objv, "addgroup name version sha256 size");
+ return TCL_ERROR;
+ } else if (reg == NULL) {
+ return TCL_ERROR;
+ } else {
+ reg_error error;
+ char* name = Tcl_GetString(objv[2]);
+ char* version = Tcl_GetString(objv[3]);
+ char* sha256 = Tcl_GetString(objv[4]);
+ Tcl_WideInt tclsize;
+ Tcl_GetWideIntFromObj(interp, objv[5], &tclsize);
+ sqlite_int64 size = (sqlite_int64)tclsize;
+ if (reg_entry_addgroup(entry, name, version, sha256, size, &error)) {
+ return TCL_OK;
+ }
+ return registry_failed(interp, &error);
+ }
+}
+
+static int entry_obj_get_portgroups(Tcl_Interp* interp, reg_entry* entry, int objc,
+ Tcl_Obj* CONST objv[]) {
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "groups_used");
+ return TCL_ERROR;
+ } else if (reg == NULL) {
+ return TCL_ERROR;
+ } else {
+ reg_portgroup** portgroups;
+ reg_error error;
+ int portgroup_count = reg_entry_getgroups(entry, &portgroups, &error);
+ if (portgroup_count >= 0) {
+ Tcl_Obj** objs;
+ int retval = TCL_ERROR;
+ if (list_portgroup_to_obj(interp, &objs, portgroups, portgroup_count, &error)){
+ Tcl_Obj* result = Tcl_NewListObj(portgroup_count, objs);
+ Tcl_SetObjResult(interp, result);
+ free(objs);
+ retval = TCL_OK;
+ } else {
+ retval = registry_failed(interp, &error);
+ }
+ free(portgroups);
+ return retval;
+ }
+ return registry_failed(interp, &error);
+ }
+}
+
</ins><span class="cx"> typedef struct {
</span><span class="cx"> char* name;
</span><span class="cx"> int (*function)(Tcl_Interp* interp, reg_entry* entry, int objc,
</span><span class="lines">@@ -391,6 +444,9 @@
</span><span class="cx"> { "dependents", entry_obj_dependents },
</span><span class="cx"> { "dependencies", entry_obj_dependencies },
</span><span class="cx"> { "depends", entry_obj_depends },
</span><ins>+ /* portgroups */
+ { "addgroup", entry_obj_add_portgroup },
+ { "groups_used", entry_obj_get_portgroups },
</ins><span class="cx"> { NULL, NULL }
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="trunkbasesrcregistry20portgroupc"></a>
<div class="addfile"><h4>Added: trunk/base/src/registry2.0/portgroup.c (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/portgroup.c         (rev 0)
+++ trunk/base/src/registry2.0/portgroup.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,294 @@
</span><ins>+/*
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sqlite3.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tcl.h>
+
+#include <cregistry/portgroup.h>
+#include <cregistry/util.h>
+
+#include "portgroup.h"
+#include "portgroupobj.h"
+#include "registry.h"
+#include "util.h"
+
+/**
+ * Converts a command name into a `reg_portgroup`.
+ *
+ * @param [in] interp Tcl interpreter to check within
+ * @param [in] name name of portgroup to get
+ * @param [out] errPtr description of error if the portgroup can't be found
+ * @return a portgroup, or NULL if one couldn't be found
+ * @see get_object
+ */
+static reg_portgroup* get_portgroup(Tcl_Interp* interp, char* name, reg_error* errPtr) {
+ return (reg_portgroup*)get_object(interp, name, "portgroup", portgroup_obj_cmd, errPtr);
+}
+
+/**
+ * Removes the portgroup from the Tcl interpreter. Doesn't actually delete it since
+ * that's the registry's job. This is written to be used as the
+ * `Tcl_CmdDeleteProc` for an portgroup object command.
+ *
+ * @param [in] clientData address of a reg_portgroup to remove
+ */
+void delete_portgroup(ClientData clientData) {
+ reg_portgroup* portgroup = (reg_portgroup*)clientData;
+ free(portgroup->proc);
+ portgroup->proc = NULL;
+}
+
+/**
+ * registry::portgroup open id name version size sha256
+ *
+ * Opens a portgroup matching the given parameters.
+ */
+static int portgroup_open(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
+        reg_registry* reg = registry_for(interp, reg_attached);
+        if (objc != 7) {
+                Tcl_WrongNumArgs(interp, 1, objv, "open id name version size sha256");
+                return TCL_ERROR;
+        } else if (reg == NULL) {
+                return TCL_ERROR;
+        } else {
+                char* id = Tcl_GetString(objv[2]);
+                char* name = Tcl_GetString(objv[3]);
+ char* version = Tcl_GetString(objv[4]);
+ char* size = Tcl_GetString(objv[5]);
+ char* sha256 = Tcl_GetString(objv[6]);
+
+                reg_error error;
+                reg_portgroup* portgroup = reg_portgroup_open(reg, id, name, version, size, sha256, &error);
+                if (portgroup != NULL) {
+                        Tcl_Obj* result;
+                        if (portgroup_to_obj(interp, &result, portgroup, NULL, &error)) {
+                                Tcl_SetObjResult(interp, result);
+                                return TCL_OK;
+                        }
+                }
+                return registry_failed(interp, &error);
+        }
+        return TCL_ERROR;
+}
+
+/**
+ * registry::portgroup close portgroup
+ *
+ * Closes a portgroup. It will remain in the registry.
+ */
+static int portgroup_close(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
+        if (objc != 3) {
+                Tcl_WrongNumArgs(interp, 1, objv, "close portgroup");
+                return TCL_ERROR;
+        } else {
+                reg_error error;
+                char* proc = Tcl_GetString(objv[2]);
+                reg_portgroup* portgroup = get_portgroup(interp, proc, &error);
+                if (portgroup == NULL) {
+                        return registry_failed(interp, &error);
+                } else {
+                        Tcl_DeleteCommand(interp, proc);
+                        return TCL_OK;
+                }
+        }
+}
+
+typedef struct {
+ char* name;
+ reg_strategy strategy;
+} strategy_type;
+
+static strategy_type strategies[] = {
+ { "-exact", reg_strategy_exact },
+ { "-glob", reg_strategy_glob },
+ { "-regexp", reg_strategy_regexp },
+ { "-null", reg_strategy_null },
+ { "--", reg_strategy_exact },
+ { NULL, 0 }
+};
+
+/*
+ * registry::portgroup search ?key value ...?
+ *
+ * Searches the registry for portgroups for which each key's value is equal to the
+ * given value. To find all portgroups, call `portgroup search` with no key-value pairs.
+ * For each key, can be given an option of -exact, -glob, -regexp or -null to
+ * specify the matching strategy; defaults to exact.
+ */
+static int portgroup_search(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]) {
+ int i, j;
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ } else {
+ char** keys;
+ char** vals;
+ int* strats;
+ int key_count = 0;
+ reg_portgroup** portgroups;
+ reg_error error;
+ int portgroup_count;
+ for (i = 2; i < objc;) {
+ int index, strat_index, val_length;
+ if (Tcl_GetIndexFromObj(interp, objv[i], portgroup_props, "search key",
+ 0, &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ /* we ate the key value */
+ i++;
+
+ /* check whether there's a strategy */
+ if (Tcl_GetString(objv[i])[0] == '-'
+ && Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
+ sizeof(strategy_type), "option", 0, &strat_index)
+ != TCL_ERROR) {
+ /* this key has a strategy specified, eat the strategy parameter */
+ i++;
+
+ if (strategies[strat_index].strategy != reg_strategy_null) {
+ /* this key must also have a value */
+
+ if (Tcl_GetStringFromObj(objv[i], &val_length) == NULL
+ || val_length == 0) {
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "search ?key ?options? value ...?");
+ return TCL_ERROR;
+ }
+
+ i++;
+ }
+ } else {
+ /* this key must also have a value */
+
+ if (Tcl_GetStringFromObj(objv[i], &val_length) == NULL
+ || val_length == 0) {
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "search ?key ?options? value ...?");
+ return TCL_ERROR;
+ }
+
+ i++;
+ }
+
+ key_count++;
+ }
+
+ keys = malloc(key_count * sizeof(char*));
+ vals = malloc(key_count * sizeof(char*));
+ strats = malloc(key_count * sizeof(int));
+ if (!keys || !vals || !strats) {
+ return TCL_ERROR;
+ }
+ for (i = 2, j = 0; i < objc && j < key_count; j++) {
+ int strat_index;
+
+ keys[j] = Tcl_GetString(objv[i++]);
+
+ /* try to get the strategy */
+ if (Tcl_GetString(objv[i])[0] == '-'
+ && Tcl_GetIndexFromObjStruct(interp, objv[i], strategies,
+ sizeof(strategy_type), "option", 0, &strat_index)
+ != TCL_ERROR) {
+ /* this key has a strategy specified */
+ i++;
+
+ strats[j] = strategies[strat_index].strategy;
+ } else {
+ /* use default strategy */
+ strats[j] = reg_strategy_exact;
+ }
+
+ if (strats[j] != reg_strategy_null) {
+ vals[j] = Tcl_GetString(objv[i++]);
+ } else {
+ vals[j] = NULL;
+ }
+ }
+ portgroup_count = reg_portgroup_search(reg, keys, vals, strats, key_count,
+ &portgroups, &error);
+ free(keys);
+ free(vals);
+ free(strats);
+ if (portgroup_count >= 0) {
+ int retval;
+ Tcl_Obj* resultObj;
+ Tcl_Obj** objs;
+ if (list_portgroup_to_obj(interp, &objs, portgroups, portgroup_count, &error)){
+ resultObj = Tcl_NewListObj(portgroup_count, objs);
+ Tcl_SetObjResult(interp, resultObj);
+ free(objs);
+ retval = TCL_OK;
+ } else {
+ retval = registry_failed(interp, &error);
+ }
+ free(portgroups);
+ return retval;
+ }
+ return registry_failed(interp, &error);
+ }
+}
+
+typedef struct {
+ char* name;
+ int (*function)(Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]);
+} portgroup_cmd_type;
+
+static portgroup_cmd_type portgroup_cmds[] = {
+ /* Global commands */
+ { "open", portgroup_open },
+ { "close", portgroup_close },
+ { "search", portgroup_search },
+ { NULL, NULL }
+};
+
+/*
+ * registry::portgroup cmd ?arg ...?
+ *
+ * Commands manipulating portgroup entries in the registry. This can be called `registry::portgroup`
+ */
+int portgroup_cmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc,
+ Tcl_Obj* CONST objv[]) {
+ int cmd_index;
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObjStruct(interp, objv[1], portgroup_cmds,
+ sizeof(portgroup_cmd_type), "cmd", 0, &cmd_index) == TCL_OK) {
+ portgroup_cmd_type* cmd = &portgroup_cmds[cmd_index];
+ return cmd->function(interp, objc, objv);
+ }
+ return TCL_ERROR;
+}
</ins></span></pre></div>
<a id="trunkbasesrcregistry20portgrouph"></a>
<div class="addfile"><h4>Added: trunk/base/src/registry2.0/portgroup.h (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/portgroup.h         (rev 0)
+++ trunk/base/src/registry2.0/portgroup.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+/*
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _PORTGROUP_H
+#define _PORTGROUP_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tcl.h>
+
+void delete_portgroup(ClientData clientData);
+
+int portgroup_cmd(ClientData clientData UNUSED, Tcl_Interp* interp, int objc,
+ Tcl_Obj* CONST objv[]);
+
+#endif /* _PORTGROUP_H */
</ins></span></pre></div>
<a id="trunkbasesrcregistry20portgroupobjc"></a>
<div class="addfile"><h4>Added: trunk/base/src/registry2.0/portgroupobj.c (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/portgroupobj.c         (rev 0)
+++ trunk/base/src/registry2.0/portgroupobj.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,135 @@
</span><ins>+/*
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <tcl.h>
+#include <sqlite3.h>
+
+#include "portgroupobj.h"
+#include "registry.h"
+#include "util.h"
+
+const char* portgroup_props[] = {
+ "name",
+ "version",
+ "size",
+ "sha256",
+ NULL
+};
+
+/* ${portgroup} prop ?value? */
+static int portgroup_obj_prop(Tcl_Interp* interp, reg_portgroup* portgroup, int objc,
+ Tcl_Obj* CONST objv[]) {
+ int index;
+ if (objc > 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?value?");
+ return TCL_ERROR;
+ }
+ if (objc == 2) {
+ /* ${portgroup} prop; return the current value */
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[1], portgroup_props, "prop", 0, &index)
+ == TCL_OK) {
+ char* key = Tcl_GetString(objv[1]);
+ char* value;
+ reg_error error;
+ if (reg_portgroup_propget(portgroup, key, &value, &error)) {
+ Tcl_Obj* result = Tcl_NewStringObj(value, -1);
+ Tcl_SetObjResult(interp, result);
+ free(value);
+ return TCL_OK;
+ }
+ return registry_failed(interp, &error);
+ }
+ return TCL_ERROR;
+ } else {
+ /* ${portgroup} prop name value; set a new value */
+ reg_registry* reg = registry_for(interp, reg_attached);
+ if (reg == NULL) {
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[1], portgroup_props, "prop", 0, &index)
+ == TCL_OK) {
+ char* key = Tcl_GetString(objv[1]);
+ char* value = Tcl_GetString(objv[2]);
+ reg_error error;
+ if (reg_portgroup_propset(portgroup, key, value, &error)) {
+ return TCL_OK;
+ }
+ return registry_failed(interp, &error);
+ }
+ return TCL_ERROR;
+ }
+}
+
+typedef struct {
+ char* name;
+ int (*function)(Tcl_Interp* interp, reg_portgroup* portgroup, int objc,
+ Tcl_Obj* CONST objv[]);
+} portgroup_obj_cmd_type;
+
+static portgroup_obj_cmd_type portgroup_cmds[] = {
+ /* keys */
+ { "name", portgroup_obj_prop },
+ { "version", portgroup_obj_prop },
+ { "size", portgroup_obj_prop },
+ { "sha256", portgroup_obj_prop },
+ { NULL, NULL }
+};
+
+/* ${portgroup} cmd ?arg ...? */
+/* This function implements the command that will be called when a portgroup
+ * created by `registry::portgroup` is used as a procedure. Since all data is kept
+ * in a temporary sqlite3 database that is created for the current interpreter,
+ * none of the sqlite3 functions used have any error checking. That should be a
+ * safe assumption, since nothing outside of registry:: should ever have the
+ * chance to touch it.
+ */
+int portgroup_obj_cmd(ClientData clientData, Tcl_Interp* interp, int objc,
+ Tcl_Obj* CONST objv[]) {
+ int cmd_index;
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObjStruct(interp, objv[1], portgroup_cmds,
+ sizeof(portgroup_obj_cmd_type), "cmd", 0, &cmd_index) == TCL_OK) {
+ portgroup_obj_cmd_type* cmd = &portgroup_cmds[cmd_index];
+ return cmd->function(interp, (reg_portgroup*)clientData, objc, objv);
+ }
+ return TCL_ERROR;
+}
+
</ins></span></pre></div>
<a id="trunkbasesrcregistry20portgroupobjh"></a>
<div class="addfile"><h4>Added: trunk/base/src/registry2.0/portgroupobj.h (0 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/portgroupobj.h         (rev 0)
+++ trunk/base/src/registry2.0/portgroupobj.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+/*
+ * vim:tw=80:expandtab
+ * $Id$
+ *
+ * Copyright (c) 2014 The MacPorts Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _PORTGROUP_OBJ_CMD_H
+#define _PORTGROUP_OBJ_CMD_H
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tcl.h>
+#include <sqlite3.h>
+
+extern const char* portgroup_props[];
+
+int portgroup_obj_cmd(ClientData clientData, Tcl_Interp* interp, int objc,
+ Tcl_Obj* CONST objv[]);
+
+#endif /* _PORTGROUP_OBJ_CMD_H */
</ins></span></pre></div>
<a id="trunkbasesrcregistry20portuninstalltcl"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/portuninstall.tcl (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/portuninstall.tcl        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/portuninstall.tcl        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx">
</span><span class="cx"> proc uninstall {portname {version ""} {revision ""} {variants 0} {optionslist ""}} {
</span><span class="cx"> global uninstall.force uninstall.nochecksum UI_PREFIX \
</span><del>- macports::portimagefilepath
</del><ins>+ macports::portimagefilepath macports::registry.path
</ins><span class="cx"> array set options $optionslist
</span><span class="cx"> if {[info exists options(subport)]} {
</span><span class="cx"> # don't want this set when calling registry::run_target
</span><span class="lines">@@ -156,7 +156,7 @@
</span><span class="cx"> # look up deps from the saved portfile if possible
</span><span class="cx"> if {![catch {set mport [mportopen_installed [$port name] [$port version] [$port revision] [$port variants] $optionslist]}]} {
</span><span class="cx"> array set depportinfo [mportinfo $mport]
</span><del>- mportclose_installed $mport
</del><ins>+ mportclose $mport
</ins><span class="cx"> foreach type $deptypes {
</span><span class="cx"> if {[info exists depportinfo($type)]} {
</span><span class="cx"> foreach dep $depportinfo($type) {
</span><span class="lines">@@ -217,9 +217,37 @@
</span><span class="cx"> # files so just ignore the failure
</span><span class="cx"> catch {file delete [::file dirname $imagefile]}
</span><span class="cx">
</span><ins>+ # We want to delete the portfile if not referenced by any other ports
+ set portfile [$ref portfile]
+
+ # and likewise the portgroups
+ set portgroups [list]
+ foreach pg [$ref groups_used] {
+ lappend portgroups [list [$pg name] [$pg version] [$pg size] [$pg sha256]]
+ }
+
</ins><span class="cx"> registry::write {
</span><span class="cx"> registry::entry delete $port
</span><span class="cx"> }
</span><ins>+
+ set portfile_path [file join ${registry.path} registry portfiles ${portname}-${version}_${revision} $portfile]
+ if {[registry::entry search portfile $portfile] eq {}} {
+ file delete -force $portfile_path
+ catch {file delete [file dirname $portfile_path]}
+ }
+
+ set reg_portgroups_dir [file join ${registry.path} registry portgroups]
+ foreach pg $portgroups {
+ set pgname [lindex $pg 0]
+ set pgversion [lindex $pg 1]
+ set pgsize [lindex $pg 2]
+ set pgsha256 [lindex $pg 3]
+ if {[registry::portgroup search name $pgname version $pgversion size $pgsize sha256 $pgsha256] eq {}} {
+ set pg_reg_dir [file join $reg_portgroups_dir ${pgsha256}-${pgsize}]
+ file delete -force ${pg_reg_dir}/${pgname}-${pgversion}.tcl
+ catch {file delete $pg_reg_dir}
+ }
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> # uninstall dependencies if requested
</span></span></pre></div>
<a id="trunkbasesrcregistry20registryc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/registry.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/registry.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/registry.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> * $Id$
</span><span class="cx"> *
</span><span class="cx"> * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
</span><del>- * Copyright (c) 2012 The MacPorts Project
</del><ins>+ * Copyright (c) 2012, 2014 The MacPorts Project
</ins><span class="cx"> * All rights reserved.
</span><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include <tcl.h>
</span><span class="cx">
</span><span class="cx"> #include <cregistry/registry.h>
</span><ins>+#include <cregistry/portgroup.h>
</ins><span class="cx"> #include <cregistry/entry.h>
</span><span class="cx"> #include <cregistry/file.h>
</span><span class="cx">
</span><span class="lines">@@ -46,6 +47,7 @@
</span><span class="cx"> #include "file.h"
</span><span class="cx"> #include "graph.h"
</span><span class="cx"> #include "item.h"
</span><ins>+#include "portgroup.h"
</ins><span class="cx"> #include "registry.h"
</span><span class="cx"> #include "util.h"
</span><span class="cx">
</span><span class="lines">@@ -389,6 +391,7 @@
</span><span class="cx"> /* Tcl_CreateObjCommand(interp, "registry::item", item_cmd, NULL, NULL); */
</span><span class="cx"> Tcl_CreateObjCommand(interp, "registry::entry", entry_cmd, NULL, NULL);
</span><span class="cx"> Tcl_CreateObjCommand(interp, "registry::file", file_cmd, NULL, NULL);
</span><ins>+ Tcl_CreateObjCommand(interp, "registry::portgroup", portgroup_cmd, NULL, NULL);
</ins><span class="cx"> Tcl_CreateObjCommand(interp, "registry::metadata", metadata_cmd, NULL, NULL);
</span><span class="cx"> if (Tcl_PkgProvide(interp, "registry2", "2.0") != TCL_OK) {
</span><span class="cx"> return TCL_ERROR;
</span></span></pre></div>
<a id="trunkbasesrcregistry20registryh"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/registry.h (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/registry.h        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/registry.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx">
</span><span class="cx"> #include <tcl.h>
</span><span class="cx"> #include <sqlite3.h>
</span><ins>+#include <cregistry/portgroup.h>
</ins><span class="cx"> #include <cregistry/entry.h>
</span><span class="cx">
</span><span class="cx"> typedef struct _entry_list {
</span></span></pre></div>
<a id="trunkbasesrcregistry20registry_utiltcl"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/registry_util.tcl (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/registry_util.tcl        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/registry_util.tcl        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -103,7 +103,7 @@
</span><span class="cx"> if {[catch {set result [mportexec $mport $target]} result] || $result != 0} {
</span><span class="cx"> global errorInfo
</span><span class="cx"> ui_debug "$errorInfo"
</span><del>- catch {mportclose_installed $mport}
</del><ins>+ catch {mportclose $mport}
</ins><span class="cx"> ui_warn "Failed to execute portfile from registry for $portspec"
</span><span class="cx"> switch $target {
</span><span class="cx"> activate {
</span><span class="lines">@@ -127,7 +127,7 @@
</span><span class="cx"> if {(![info exists keeplogs] || !$keeplogs) && $target ne "activate"} {
</span><span class="cx"> catch {mportexec $mport clean}
</span><span class="cx"> }
</span><del>- mportclose_installed $mport
</del><ins>+ mportclose $mport
</ins><span class="cx"> return 1
</span><span class="cx"> }
</span><span class="cx"> } else {
</span></span></pre></div>
<a id="trunkbasesrcregistry20utilc"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/util.c (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/util.c        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/util.c        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include "util.h"
</span><span class="cx"> #include "entryobj.h"
</span><span class="cx"> #include "fileobj.h"
</span><ins>+#include "portgroupobj.h"
</ins><span class="cx">
</span><span class="cx"> /**
</span><span class="cx"> * Generates a unique proc name starting with prefix.
</span><span class="lines">@@ -214,6 +215,29 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * Sets a given name to be a portgroup object.
+ *
+ * @param [in] interp Tcl interpreter to create the portgroup within
+ * @param [in] name name to associate the given portgroup with
+ * @param [in] portgroup portgroup to associate with the given name
+ * @param [out] errPtr description of error if it couldn't be set
+ * @return true if success; false if failure
+ * @see set_object
+ */
+int set_portgroup(Tcl_Interp* interp, char* name, reg_portgroup* portgroup,
+ reg_error* errPtr) {
+ if (set_object(interp, name, portgroup, "portgroup", portgroup_obj_cmd, NULL,
+ errPtr)) {
+ portgroup->proc = strdup(name);
+ if (!portgroup->proc) {
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/**
</ins><span class="cx"> * Reports a sqlite3 error to Tcl.
</span><span class="cx"> *
</span><span class="cx"> * Queries the database for the most recent error message and sets it as the
</span><span class="lines">@@ -297,6 +321,23 @@
</span><span class="cx"> return 1;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+int portgroup_to_obj(Tcl_Interp* interp, Tcl_Obj** obj, reg_portgroup* portgroup,
+ int* lower_bound, reg_error* errPtr) {
+ if (portgroup->proc == NULL) {
+ char* name = unique_name(interp, "::registry::portgroup", lower_bound);
+ if (!name) {
+ return 0;
+ }
+ if (!set_portgroup(interp, name, portgroup, errPtr)) {
+ free(name);
+ return 0;
+ }
+ free(name);
+ }
+ *obj = Tcl_NewStringObj(portgroup->proc, -1);
+ return 1;
+}
+
</ins><span class="cx"> int list_entry_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
</span><span class="cx"> reg_entry** entries, int entry_count, reg_error* errPtr) {
</span><span class="cx"> int lower_bound = 0;
</span><span class="lines">@@ -311,6 +352,13 @@
</span><span class="cx"> (void***)objs, (void**)files, file_count, errPtr);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+int list_portgroup_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
+ reg_portgroup** portgroups, int portgroup_count, reg_error* errPtr) {
+ int lower_bound = 0;
+ return recast(interp, (cast_function*)portgroup_to_obj, &lower_bound, NULL,
+ (void***)objs, (void**)portgroups, portgroup_count, errPtr);
+}
+
</ins><span class="cx"> static int obj_to_string(void* userdata UNUSED, char** string, Tcl_Obj* obj,
</span><span class="cx"> void* param UNUSED, reg_error* errPtr UNUSED) {
</span><span class="cx"> *string = Tcl_GetString(obj);
</span></span></pre></div>
<a id="trunkbasesrcregistry20utilh"></a>
<div class="modfile"><h4>Modified: trunk/base/src/registry2.0/util.h (117406 => 117407)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/base/src/registry2.0/util.h        2014-02-25 16:10:21 UTC (rev 117406)
+++ trunk/base/src/registry2.0/util.h        2014-02-25 18:28:14 UTC (rev 117407)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include <sqlite3.h>
</span><span class="cx">
</span><span class="cx"> #include <cregistry/registry.h>
</span><ins>+#include <cregistry/portgroup.h>
</ins><span class="cx"> #include <cregistry/entry.h>
</span><span class="cx"> #include <cregistry/file.h>
</span><span class="cx">
</span><span class="lines">@@ -60,6 +61,8 @@
</span><span class="cx"> reg_error* errPtr);
</span><span class="cx"> int set_file(Tcl_Interp* interp, char* name, reg_file* file,
</span><span class="cx"> reg_error* errPtr);
</span><ins>+int set_portgroup(Tcl_Interp* interp, char* name, reg_portgroup* portgroup,
+ reg_error* errPtr);
</ins><span class="cx">
</span><span class="cx"> void set_sqlite_result(Tcl_Interp* interp, sqlite3* db, const char* query);
</span><span class="cx">
</span><span class="lines">@@ -77,6 +80,10 @@
</span><span class="cx"> int* lower_bound, reg_error* errPtr);
</span><span class="cx"> int list_file_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
</span><span class="cx"> reg_file** files, int file_count, reg_error* errPtr);
</span><ins>+int portgroup_to_obj(Tcl_Interp* interp, Tcl_Obj** ibj, reg_portgroup* portgroup,
+ int* lower_bound, reg_error* errPtr);
+int list_portgroup_to_obj(Tcl_Interp* interp, Tcl_Obj*** objs,
+ reg_portgroup** portgroups, int portgroup_count, reg_error* errPtr);
</ins><span class="cx">
</span><span class="cx"> void free_strings(void* userdata UNUSED, char** strings, int count);
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>