How to parse a Portfile?

Frank Stock fstock at bytelightning.com
Sat Dec 2 04:22:08 UTC 2023


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 <jmr at macports.org> 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



More information about the macports-dev mailing list