Thank you for that detailed explanation Josh!
It provided all the missing pieces I needed.
-Frank
For future searches of this mailing list, here is a nodejs app based on Josh’s
explanation.
You need to use the npm package ’tcl’ (’tcl-js’ does not seem to support
packages).
However, ’tcl’ uses native bindings, so node-gyp failed on my machine because
the Tcl.framework does not publish a tclConfig.sh file.
Good news is that MacPorts embeds its own Tcl impl, so you can bind to that (no
need to even install the ’tcl’ port).
I did have to double declare the TCLCONFIG env var for some reason…
GYP_DEFINES="TCLCONFIG=/opt/local/libexec/macports/lib/tclConfig.sh"
TCLCONFIG=/opt/local/libexec/macports/lib/tclConfig.sh npm install tcl --save
Once the ’tcl’ package is installed in node_modules, the app is simple
// Dump all the key names found in the ‘portinfo’ array to the console.
// Also log the value of the ‘homepage’ key.
const { Tcl } = require('tcl');
(async (portName: string) => {
const tcl = new Tcl();
// Let the interpreter know it can find the macports package
// inside base/libexec/macports/lib
tcl.$('lappend auto_path /opt/local/libexec/macports/lib');
tcl.$('package require macports');
tcl.$('mportinit');
tcl.$(`lassign [mportlookup ${portName}] - infolist`);
tcl.$('array set portinfo $infolist');
tcl.$('set mport [mportopen $portinfo(porturl) [list subport
$portinfo(name)] ""]');
tcl.$('array set portinfo [mportinfo $mport]’);
// Write all the key names to stdout.
tcl.$(`foreach key [array names portinfo] { puts $key }`);
// Log the value of the homepage key to the console.
const result = tcl.$('_mportkey $mport homepage');
console.log('homepage=' + result.data());
})('zlib');
> On Nov 30, 2023, at 7:05 PM, Joshua Root <[email protected]> wrote:
>
> On 1/12/2023 11:27, Frank Stock wrote:
>> Section 6.4.1 has an interesting bullet…
>> "Ports API - API for Portfile parsing and execution”
>> I would like to extract information from a Portfile such as, version,
>> license, add_users, startupitem, post-destroot, etc. for analysis/processing
>> in a Node.js app.
>> Thought I might be able to use a Tcl Interpreter such as npm tcl or npm
>> tcl-js to load from base/src/port1.0/ and obtain what I want using mportinfo.
>> But I confess, being a newbie to Tcl as well as MacPorts internals, after a
>> day of “grep”, I still haven’t figured out how (or even if its possible) to
>> load the API into an interpreter outside MacPorts?
>> Are there better ways to accomplish my goal of extracting Portfile info?
>> Wish I could just use “port info acme”, but add_users and post-destroot are
>> some of the required pieces of info I need.
>
> Portfiles can contain arbitrary Tcl code and rely heavily on the code in
> MacPorts base, so no, there's not really any way to correctly evaluate them
> without using the macports API. There are quite a few examples in the
> macports-contrib repo. Basic usage goes like this:
>
> package require macports
> mportinit
>
> set portname python311
> # Look up the port name in the PortIndex
> lassign [mportlookup $portname] - infolist
> array set portinfo $infolist
>
> # Use the porturl and subport from the index to open the Portfile
> set mport [mportopen $portinfo(porturl) [list subport $portinfo(name)] ""]
>
> # Update the portinfo array with information that is not in the index
> array set portinfo [mportinfo $mport]
>
>
> At this point you have a portinfo array containing all the public information
> about the port. For internals like add_users you would have to use a private
> API like _mportkey:
>
> _mportkey $mport add_users
>
> That can get you the values of Portfile variables, but note that
> post-destroot is not a variable, it's a procedure.
>
> It is possible to get at the Portfile interpreter and run arbitrary code in
> it, but needless to say at that point it's totally unsupported and subject to
> change without notice, you're on your own, etc.
>
> set workername [ditem_key $mport workername]
> $workername eval [list info procs]
>
> - Josh