Version 7 of github::github

Updated 2020-03-19 09:46:51 by DDG

Introduction

DDG 2020-03-19: (WIP) I had to play around a little bit with the GO programming language by compiling the webview go library . I found it quite nice to directly download packages from github to your package directory using go get. This used git in the background, so the go approach needed a working installation of git which again needed installs of Perl, Tcl, ... around 6000 individual files and 650MB hard disk space. Can we do some small scale thing for Tcl here which works in a similar way. We need a Tcl interpreter, the package tls for the https protocol and finally the json library of Tcllib to parse the json output of the github api. The goal is to download only the required parts of other packages to a parallel directory of your package you are developing.

Here is some preliminary code which allows to download individual folders from a github repo:

#!/usr/bin/env tclsh
# file github/github.tcl

# chicken and egg problem we need non-standard packages tls and json ...
package require tls
package require http
::http::register https 443 ::tls::socket

namespace eval ::github {
    variable libdir [file normalize [file join [file dirname [info script]] ..]]
    if {[lsearch $::auto_path $libdir] == -1} {
        lappend auto_path $libdir
    }
} 

# I already placed the json folder below of the github folder
package require json

proc ::github::github {cmd owner repo folder package} {
    variable libdir
    set url https://api.github.com/repos/$owner/$repo/contents/$folder/$package
    set data [http::data [http::geturl $url]]
    #puts $data
    set d [json::json2dict $data]
    set l [llength $d]
    set files [list]
    for {set i 0} {$i < $l} {incr i 1} {
        
        set file [dict get [dict create {*}[lindex $d $i]] download_url]
        lappend files $file
    }
    #puts [lindex $d 1]
    set folder [file join [lindex $::auto_path end] $package]
    if {$cmd eq "import" && [file exists $folder]} {
        return
    } elseif {$cmd eq "update" && [file exists $folder]} {
        file delete $folder
    }
    file mkdir $folder
    # TODO subfolders
    foreach file $files {
        puts "fetching $file"
        set fname [file tail $file]
        set f [open $fname w]
        fconfigure $f -translation binary
        set tok [http::geturl $file -channel $f]
        set Stat [::http::status $tok]
        flush $f
        close $f
        http::cleanup $tok
    }
}

If we have this we can do the following:

package require github
github::github import tcltk tcllib modules snit
puts [package require snit]
  • github::github import checks if the package was already downloaded, if not downloads and installs it
  • github::github update deletes any existing package folder for the package and then it does a re(import)

Missing

  • no recursive folders yet
  • check for dependencies, seems to be very difficult, dependent packages might be somewhere and as well not on github
  • chose an other directory, not the parallel on, this would offer the possibility to install packages as well outside of a starkit

Discussion

Please discuss here, I am open for suggestions:

DDG 2020-03-19: I know you can install snit by installing all of tcllib. But I think this approach has as well its charm, as it only takes what you really need. And sometimes it is nice to fetch packages which are not in TEA repositories but only on github.