Central Coordination Bureau

Found at: https://chiselapp.com/user/stwo/repository/central

Stu 2022-09-05 Version 1.0b2.
Stu 2022-08-22 Version 1.0b1.


The Central Coordination Bureau is an oversight
office whose purpose is to help Tcl programs
to get around and along in the big scary world.


Central is a passive registration system for Tcl extensions and programs,
based on the idea and workings of the Tcl *pkgconfig* command.
To participate, a *pkgconfig* command should exist in the namespace
of an extension or program ("package").
Central itself is not needed by a providing package, only by a querying program.

Central can be used by a program to scan the namespace hierarchy (*discover*),
and query any package information found.

The *pkgconfig* command provided by a package should
behave like the Tcl *pkgconfig* command.

Central makes no effort to interpret the information returned by a
*pkgconfig* command; this information is entirely up to the package.

Central is all about "about": allowing a program to easily
provide information about itself to the outside world.

The usage example files, the program centraltool.tcl, and
the Central extension itself contain *pkgconfig* commands and other
code bits that can be copied or serve as examples and should make it easy
to add Central functionality to extensions or programs.
Central works with Jim as well as with Tcl.

Centralized Packages

It is only a convention that
(Tcl package name) == (package namespace) == (export namespace).
Oftentimes, documentation or source code must be consulted
to determine where to find commands exported by a package.

A "centralized" package connects a Tcl package name and a namespace.

A package is considered "centralized" if it has both "name" and "importfrom" keys.
The "name" should be the name of the Tcl package used in package require,
and "importfrom" should be the namespace where procedures exported by the package can be found.
The "importfrom" namespace will be used in namespace import invocations.
If "importfrom" is empty then the package is still considered to be centralized.

Package Initialization

A package can declare an initialization command by having both "name" and "initializer" keys.
A package that declares both keys can be used with the [central initializer] and [central initialize] commands.


These examples use the centralized packages found on this page.
Note that a pkgconfig is mostly boilerplate;
only the package dictionary requires updating when copying the pkgconfig
code to a new program, making for easy Central participation.

package require central
namespace import central::central

package require somePackage
package require AnotherPackage

central discover

central import somePackage
central import AnotherPackage sameDay anotherDay

puts [lastDay]
puts [someDay]

puts [sameDay]
puts [anotherDay]

Example pkgconfig for Tcl or Jim

namespace eval SomePkg {

proc pkgconfig {subcommand args} {
        if {$subcommand ni [list get list]} {
                return -code error "unknown subcommand \"$subcommand\": must be get, or list"
        set pkgconfig [dict create {*}{
                name   somePackage
                title  {Some Package}
                author {A Programmer}
                date   {2022/09/04}
        dict set pkgconfig importfrom [namespace current]

        return -code {*}[expr {
            $subcommand eq "list"
                ? [llength $args] == 0
                    ? [list ok [dict keys $pkgconfig]]
                    : [list error "wrong # args: should be \"[namespace current]::pkgconfig list\""]
                : $subcommand eq "get"
                    ? [llength $args] == 1
                        ? [dict exists $pkgconfig [set key [lindex $args 0]]]
                            ? [list ok [dict get $pkgconfig $key]]
                            : [list error "key \"$key\" not known"]
                        : [list error "wrong # args: should be \"[namespace current]::pkgconfig get key\""]
                    : [list uh oh]
}; # pkgconfig

# For the examples on this page

proc lastDay {} { return yesterday }
proc someDay {} { return sure      }

namespace export lastDay someDay

package provide somePackage 1.0

}; # namespace eval SomePkg

Example pkgconfig for Tcl

namespace eval an_pkg {

namespace eval pkgconfig {
        variable pkgconfig [dict create {*}{
                name    AnotherPackage
                site    http://a.site.weeb
                beta    maybe
                flavour lemon
        dict set pkgconfig importfrom [namespace parent]

        proc list {} { variable pkgconfig; return [dict keys $pkgconfig] }
        proc get {key} {
                variable pkgconfig
                if {[dict exists $pkgconfig $key]} {
                        return [dict get $pkgconfig $key]
                } else {
                        return -code error "key \"$key\" not known"
        namespace export get list
        namespace ensemble create
}; # pkgconfig

# For the examples on this page

proc    sameDay {} { return today    }
proc anotherDay {} { return tomorrow }

namespace export sameDay anotherDay

package provide AnotherPackage 1.0

}; # namespace eval an_pkg