pax_global_header 0000666 0000000 0000000 00000000064 12556743566 0014535 g ustar 00root root 0000000 0000000 52 comment=4fe370d513369a4ec56158088d9d345ee1114641
deken-0.1/ 0000775 0000000 0000000 00000000000 12556743566 0012463 5 ustar 00root root 0000000 0000000 deken-0.1/.gitignore 0000664 0000000 0000000 00000000067 12556743566 0014456 0 ustar 00root root 0000000 0000000 .*.swp
virtualenv*
build
workspace
deken.cfg
.DS_Store
deken-0.1/LICENSE.txt 0000664 0000000 0000000 00000003041 12556743566 0014304 0 ustar 00root root 0000000 0000000 This software is copyrighted by Chris McCormick and others. The following
terms (the "Standard Improved BSD License") apply to all files associated with
the software unless explicitly disclaimed in individual files:
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.
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior
written permission.
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.
deken-0.1/README.md 0000664 0000000 0000000 00000012213 12556743566 0013741 0 ustar 00root root 0000000 0000000 A minimal package management system for Pure Data externals.

Packages are stored on and can be installed using the `Help -> Find Packages` menu after installing the [TCL plugin](https://raw.githubusercontent.com/pure-data/deken/master/deken-plugin.tcl).
## Download ##
Click to download [deken-plugin.tcl](https://raw.githubusercontent.com/pure-data/deken/master/deken-plugin.tcl) and save it to your Pd folder:
* Linux = `~/pd-externals/deken-plugin/`
* OSX = `~/Library/Pd/deken-plugin/`
* Windows = `%AppData%\Pd\deken-plugin\`
Then select `Help -> Find Packages` and type the name of the external you would like to search for.
## Trusting packages
The `deken-plugin` will help you find and install Pd-libraries.
However, it does not verify whether a given package is downloaded from a trusted source or not.
As of now, the default package source is http://puredata.info.
Anybody who has an account on that website (currently that's a few thousand people) can upload packages,
that the `deken-plugin` will happily find and install for you.
In order to make these packages more trustworthy, we ask people to sign their uploaded packages with the GPG-key.
Unfortunately the deken-plugin does not check these signatures yet.
If you are concerned about the authenticity of a given download, you can check the GPG-signature manually,
by following these steps:
- Navigate to `Help -> Find Packages` and search for an external
- Hover your mouse over one of the search results
- At the bottom of the search window, a download link will appear
- Remember this link! (e.g. http://puredata.info/Members/the-bfg/software/frobscottle-1.10-externals.zip)
- Append `.asc` to the link (e.g. http://puredata.info/Members/the-bfg/software/frobscottle-1.10-externals.zip.asc)
- Download the GPG-signature from the link (besides the downloaded archive)
- Run `gpg --verify` on the downloaded file
If the signature is correct, you can decide yourself whether you actually trust the person who signed:
- Do you trust the signature to be owned by the person?
- Do you know the person?
- Do you trust them enough to let them install arbitrary software on your machine?
# Developers #
You can use the [`deken` command line tool](https://raw.githubusercontent.com/pure-data/deken/master/deken) to create packaged zipfiles with the correct searchable architectures in the filename, for example `freeverb~-v0.1-(Linux-amd64-64)-externals.zip`.
If you don't want to use the `deken` packaging tool you can zip and upload the files yourself. See the "Filename format" section below.
## Get started ##
$ curl https://raw.githubusercontent.com/pure-data/deken/master/deken > ~/bin/deken
$ chmod 755 ~/bin/deken
$ deken
This is your first time running deken on this machine.
I'm going to install myself and my dependencies into ~/.deken now.
Feel free to ctrl-C now if you don't want to do this.
...
See [config.md](./config.md) for deken's configuration file format.
## Create and Upload a package ##
You have a directory containing your compiled externals object files called `my_external`.
This command will create a file like `my_external-v0.1-(Linux-amd64-64)-externals.zip` and upload it to your account on where the search plugin can find it:
$ deken package -v 0.1 my_external
$ deken upload my_external
You can also just call the 'upload' directly and it will call the package command for you in one step:
$ deken upload -v 0.1 my_external
The upload step will also generate a .sha256 checksum file and upload it along with the zip file.
## Filename format ##
The `deken` tool names a zipfile of externals binaries with a specific format to be optimally searchable on [puredata.info](http://puredata.info/):
NAME[-VERSION-](ARCH1)(ARCH2)(ARCHX...)-externals.zip
* NAME is the name of the externals package ("zexy", "cyclone", "freeverb~").
* -VERSION- is an optional section which can contain version information for the end user.
* (ARCH1)(ARCH2) etc. are architecture specifiers for each type of architecture the externals are compiled for within this zipfile.
Note that the zipfile should contain a single directory at the top level with NAME the same as the externals package itself. For example a freeverb~ externals package would contain a directory "freeverb~" at the top level of the zipfile in which the externals live.
The square brackets around the "-VERSION-" section are to indicate it is optional, don't include them. The round braces "(" around architectures are included to separate the architectures visibly from eachother.
Some examples:
freeverb~(Windows-i386-32)-externals.zip
freeverb~(Linux-armv6-32)-externals.zip
cyclone-0.1_alpha57(Linux-x86_64-64)-externals.zip
freeverb~(Darwin-i386-32)(Darwin-x86_64-32)(Linux-armv6-32)-externals.zip
## Upgrade ##
$ deken upgrade
... self upgrades the scripts ...
## Show help ##
$ deken -h
## Platform ##
OSX Example
$ deken --platform
Darwin-i386-64bit
Linux example
$ deken --platform
Linux-x86_64-64bit-ELF
Raspbian
$ deken --platform
Linux-armv6l-32bit-ELF
deken-0.1/builder.md 0000664 0000000 0000000 00000001675 12556743566 0014444 0 ustar 00root root 0000000 0000000 Deken can also be used to build some externals directly from a repository.
## Build an external from a repository ##
$ deken build svn://svn.code.sf.net/p/pure-data/svn/trunk/externals/freeverb~/
Deken 0.1
Checking out svn://svn.code.sf.net/p/pure-data/svn/trunk/externals/freeverb~/ into ./workspace/externals/freeverb~
Building ./workspace/externals/freeverb~
## Build and install an external from a repository ##
$ deken install svn://svn.code.sf.net/p/pure-data/svn/trunk/externals/freeverb~/
Deken 0.1
Updating ./workspace/externals/freeverb~
Building ./workspace/externals/freeverb~
Installing ./workspace/externals/freeverb~ into ./pd-externals/freeverb~
## Manage Pd version ##
Show Pd version:
$ deken pd
Deken 0.1
Pd version 0.43 checked out
Change Pd version:
$ deken pd master
Deken 0.1
Pd version master checked out
### How to make your externals compatible ###
deken-0.1/config.md 0000664 0000000 0000000 00000000707 12556743566 0014256 0 ustar 00root root 0000000 0000000 Deken's config file lives in `~/.deken/config`.
Here are the possible values:
* `username` = Username on puredata.info for uploads.
* `password` = Password on puredata.info for uploads.
* `gpg_home` = Path to treat as GPG's homedir - defaults to GPG's default.
* `key_id` = The key ID to use when signing binary packages - defaults to your secret key.
* `gpg_agent` = Tell deken to invoke GPG with the `--use-agent` flag.
All values are optional.
deken-0.1/deken 0000775 0000000 0000000 00000011154 12556743566 0013501 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
# Ensure this file is executable via `chmod a+x deken`, then place it
# somewhere on your $PATH, like ~/bin. The rest of Deken will self-install
# on first run into the ~/.deken/ directory.
# Much of this code is pilfered from Clojure's Leiningen tool
export DEKEN_VERSION="0.1"
if [ $(id -u) -eq 0 ] && [ "$DEKEN_ROOT" = "" ]; then
echo "WARNING: You're currently running as root; probably by accident."
echo "Press control-C to abort or Enter to continue as root."
echo "Set DEKEN_ROOT to disable this warning."
read _
fi
if [ "$OSTYPE" = "cygwin" ] || [ "$OSTYPE" = "msys" ]; then
delimiter=";"
else
delimiter=":"
fi
if [ "$OSTYPE" = "cygwin" ]; then
cygwin=true
else
cygwin=false
fi
# This needs to be defined before we call HTTP_CLIENT below
if [ "$HTTP_CLIENT" = "" ]; then
if which curl >/dev/null; then
if [ "$https_proxy" != "" ]; then
CURL_PROXY="-x $https_proxy"
fi
HTTP_CLIENT="curl $CURL_PROXY -f -L -o"
else
HTTP_CLIENT="wget -O"
fi
fi
export DEKEN_HOME="${DEKEN_HOME:-"$HOME/.deken"}"
DEKEN_BASE_URL="https://raw.githubusercontent.com/pure-data/deken/master"
if $cygwin; then
export DEKEN_HOME=$(cygpath -w "$DEKEN_HOME")
fi
error() {
echo "$@" 1>&2
}
bail_install() {
error "Self-installation of Deken failed."
error "Please paste any errors in the bug tracker at https://github.com/pure-data/deken/issues"
# remove all trace of our attempts to install.
rm -rf $DEKEN_HOME;
# bail from this script.
exit 1;
}
bail_install_msg() {
error "$@"
bail_install
}
install_virtualenv() {
echo "Downloading & installing Virtualenv."
rm -rf $DEKEN_HOME/virtualenv-source
mkdir -p $DEKEN_HOME/virtualenv-source && \
$HTTP_CLIENT $DEKEN_HOME/virtualenv.tar.gz https://pypi.python.org/packages/source/v/virtualenv/virtualenv-12.1.1.tar.gz && \
tar -zxvf $DEKEN_HOME/virtualenv.tar.gz -C $DEKEN_HOME/virtualenv-source/ && \
mv $DEKEN_HOME/virtualenv-source/virtualenv-*/* $DEKEN_HOME/virtualenv-source
[ -d "$DEKEN_HOME/virtualenv-source" ] && (\
cd $DEKEN_HOME/virtualenv-source && \
/usr/bin/env python setup.py build ) \
|| bail_install;
}
install_deken() {
which python >/dev/null || \
bail_install_msg "Oops, no Python found! You need Python to run Deken."
which make >/dev/null || \
bail_install_msg "Oops, no Make found! You need Make to run Deken."
error "This is your first time running deken on this machine."
error "I'm going to install myself and my dependencies into ~/.deken now."
error "Feel free to ctrl-C now if you don't want to do this."
sleep 3;
[ -d "$DEKEN_HOME" ] || mkdir -p $DEKEN_HOME;
[ -e "$DEKEN_HOME/requirements.txt" ] || (\
( echo "Fetching Python requirements file: $DEKEN_BASE_URL/requirements.txt" && \
$HTTP_CLIENT $DEKEN_HOME/requirements.txt $DEKEN_BASE_URL/requirements.txt ) || bail_install)
[ -e "$DEKEN_HOME/requirements.txt" ] || bail_install
[ -e "$DEKEN_HOME/deken.hy" ] || (\
( echo "Fetching main hylang file: $DEKEN_BASE_URL/deken.hy" && \
$HTTP_CLIENT $DEKEN_HOME/deken.hy $DEKEN_BASE_URL/deken.hy ) || bail_install)
[ -e "$DEKEN_HOME/deken.hy" ] || bail_install
[ -x "$DEKEN_HOME/virtualenv-source/virtualenv.py" ] || install_virtualenv;
[ -d "$DEKEN_HOME/virtualenv" ] || (\
echo "Setting up the virtual environment." && \
$DEKEN_HOME/virtualenv-source/virtualenv.py "$DEKEN_HOME/virtualenv" || exit 1)
[ -x "$DEKEN_HOME/virtualenv/bin/hy" ] || (\
echo "Installing deken library dependencies." && \
$DEKEN_HOME/virtualenv/bin/pip install -r $DEKEN_HOME/requirements.txt || exit 1)
}
upgrade_deken() {
# first upgrade this script itself
echo "Upgrading $0."
$HTTP_CLIENT $0 $DEKEN_BASE_URL/deken
# next upgrade our dependencies
for f in requirements.txt deken.hy;
do
echo "Fetching $f file: $DEKEN_BASE_URL/$f";
$HTTP_CLIENT $DEKEN_HOME/.upgrade-$f $DEKEN_BASE_URL/$f || ( error "Error upgrading $f"; exit 1; );
mv $DEKEN_HOME/.upgrade-$f $DEKEN_HOME/$f;
done
# finally update the python dependencies
$DEKEN_HOME/virtualenv/bin/pip install -r $DEKEN_HOME/requirements.txt
echo "Successfully upgraded."
}
# make sure we are deployed
[ -d "$DEKEN_HOME" ] || install_deken
# last check to make sure we can bootstrap
[ -d "$DEKEN_HOME" ] || bail_install;
# catch the special "upgrade" command
[ "$1" = "upgrade" ] && \
# run he upgrade command instead
upgrade_deken || \
# run the real deken command with args passed through
$DEKEN_HOME/virtualenv/bin/hy $DEKEN_HOME/deken.hy $@
deken-0.1/deken-plugin.tcl 0000664 0000000 0000000 00000055422 12556743566 0015561 0 ustar 00root root 0000000 0000000 # META NAME PdExternalsSearch
# META DESCRIPTION Search for externals zipfiles on puredata.info
# META AUTHOR chris@mccormick.cx
# ex: set setl sw=2 sts=2 et
# Search URL:
# http://puredata.info/search_rss?SearchableText=xtrnl-
# The minimum version of TCL that allows the plugin to run
package require Tcl 8.4
# If Tk or Ttk is needed
#package require Ttk
# Any elements of the Pd GUI that are required
# + require everything and all your script needs.
# If a requirement is missing,
# Pd will load, but the script will not.
package require http 2
package require pdwindow 0.1
package require pd_menucommands 0.1
namespace eval ::deken:: {
namespace export open_searchui
variable mytoplevelref
variable platform
variable architecture_substitutes
variable installpath
variable statustext
variable statustimer
variable backends
namespace export register
}
namespace eval ::deken::search:: { }
set ::deken::statustimer ""
set ::deken::backends [list]
proc ::deken::register {fun} {
lappend ::deken::backends $fun
}
proc ::deken::get_writable_dir {paths} {
set fs [file separator]
set access [list RDWR CREAT EXCL TRUNC]
foreach p $paths {
if { [ catch { file mkdir $p } ] } {}
for {set i 0} {True} {incr i} {
set tmpfile "${p}${fs}dekentmp.${i}"
if {![file exists $tmpfile]} {
break
}
}
# try creating tmpfile
if {![catch {open $tmpfile $access} channel]} {
close $channel
file delete $tmpfile
return $p
}
}
return
}
# list-reverter (compat for tcl<8.5)
if {[info command lreverse] == ""} {
proc lreverse list {
set res {}
set i [llength $list]
while {$i} {
lappend res [lindex $list [incr i -1]]
}
set res
} ;# RS
}
## where to look for the config-files:
## - near the deken-plugin.tcl file
## + at some user-specific place (e.g. ~/pd-externals/deken-plugin/)
## it's probably easiest to iterate through curdir and ::sys_staticpath (in reverse order)
## and read all (existing) configurations
#
## the configfile's format is simple:
# the first element of a line is the variable name, the rest the value. e.g.
# foo bar baz
# will create a variable '::deken::foo' with value [list bar baz]
## LATER: this is rather insecure, as it allows people to overwrite
## virtually everything... (e.g. ::deken::search_for)
proc ::deken::readconfig {paths filename} {
proc doreadconfig {fname} {
if {[file exists $fname]} {
set fp [open $fname r]
while {![eof $fp]} {
set data [gets $fp]
if { [string is list $data ] } {
if { [llength $data ] > 1 } {
set ::deken::[lindex $data 0] [lrange $data 1 end]
}
}
}
return True
}
return False
}
set fs [file separator]
doreadconfig "$::current_plugin_loadpath${fs}${filename}"
foreach p0 [lreverse $paths] {
foreach p1 [ list "" "${fs}deken-plugin" ] {
doreadconfig "${p0}${p1}${fs}${filename}"
}
}
}
::deken::readconfig $::sys_staticpath deken-plugin.conf
if { [ info exists ::deken::installpath ] } {
set ::deken::installpath [ ::deken::get_writable_dir [list $::deken::installpath ] ]
} {
set ::deken::installpath [ ::deken::get_writable_dir $::sys_staticpath ]
}
# console message to let them know we're loaded
::pdwindow::post "deken-plugin.tcl (Pd externals search) in $::current_plugin_loadpath loaded.\n"
if { "$::deken::installpath" == "" } {
::pdwindow::error "deken: No writeable directory found in:\n"
foreach p $::sys_staticpath { ::pdwindow::error "\t- $p\n" }
::pdwindow::error "deken: Will not be able to download/install libraries\n"
}
set ::deken::platform(os) $::tcl_platform(os)
set ::deken::platform(machine) $::tcl_platform(machine)
set ::deken::platform(bits) [ expr [ string length [ format %X -1 ] ] * 4 ]
# normalize W32 OSs
if { [ string match "Windows *" "$::deken::platform(os)" ] > 0 } {
# we are not interested in the w32 flavour, so we just use 'Windows' for all of them
set ::deken::platform(os) "Windows"
}
# normalize W32 CPUs
if { "Windows" eq "$::deken::platform(os)" } {
# in redmond, intel only produces 32bit CPUs,...
if { "intel" eq "$::deken::platform(machine)" } { set ::deken::platform(machine) "i386" }
# ... and all 64bit CPUs are manufactured by amd
#if { "amd64" eq "$::deken::platform(machine)" } { set ::deken::platform(machine) "x86_64" }
}
::pdwindow::post "Platform detected: $::deken::platform(os)-$::deken::platform(machine)-$::deken::platform(bits)bit\n"
# architectures that can be substituted for eachother
array set ::deken::architecture_substitutes {}
set ::deken::architecture_substitutes(x86_64) [list "amd64" "i386" "i586" "i686"]
set ::deken::architecture_substitutes(amd64) [list "x86_64" "i386" "i586" "i686"]
set ::deken::architecture_substitutes(i686) [list "i586" "i386"]
set ::deken::architecture_substitutes(i586) [list "i386"]
set ::deken::architecture_substitutes(armv6l) [list "armv6" "arm"]
set ::deken::architecture_substitutes(armv7l) [list "armv7" "armv6l" "armv6" "arm"]
set ::deken::architecture_substitutes(PowerPC) [list "ppc"]
set ::deken::architecture_substitutes(ppc) [list "PowerPC"]
proc ::deken::status {msg} {
#variable mytoplevelref
#$mytoplevelref.results insert end "$msg\n"
#$mytoplevelref.status.label -text "$msg"
after cancel $::deken::statustimer
if {"" ne $msg} {
set ::deken::statustext "STATUS: $msg"
set ::deken::statustimer [after 5000 [list set ::deken::statustext ""]]
} {
set ::deken::statustext ""
}
}
proc ::deken::post {msg {tag ""}} {
variable mytoplevelref
$mytoplevelref.results insert end "$msg\n" $tag
}
proc ::deken::clearpost {} {
variable mytoplevelref
$mytoplevelref.results delete 1.0 end
}
proc ::deken::bind_posttag {tag key cmd} {
variable mytoplevelref
$mytoplevelref.results tag bind $tag $key $cmd
}
proc ::deken::highlightable_posttag {tag} {
variable mytoplevelref
::deken::bind_posttag $tag \
"$mytoplevelref.results tag add highlight [ $mytoplevelref.results tag ranges $tag ]"
::deken::bind_posttag $tag \
"$mytoplevelref.results tag remove highlight [ $mytoplevelref.results tag ranges $tag ]"
# make sure that the 'highlight' tag is topmost
$mytoplevelref.results tag raise highlight
}
proc ::deken::update_searchbutton {mytoplevel} {
if { [$mytoplevel.searchbit.entry get] == "" } {
$mytoplevel.searchbit.button configure -text [_ "Show all" ]
} {
$mytoplevel.searchbit.button configure -text [_ "Search" ]
}
}
# this function gets called when the menu is clicked
proc ::deken::open_searchui {mytoplevel} {
if {[winfo exists $mytoplevel]} {
wm deiconify $mytoplevel
raise $mytoplevel
} else {
::deken::create_dialog $mytoplevel
$mytoplevel.results tag configure error -foreground red
$mytoplevel.results tag configure warn -foreground orange
$mytoplevel.results tag configure info -foreground grey
$mytoplevel.results tag configure highlight -foreground blue
$mytoplevel.results tag configure archmatch -foreground black
$mytoplevel.results tag configure noarchmatch -foreground grey
}
::deken::post "To get a list of all available externals, try an empty search." info
}
# build the externals search dialog window
proc ::deken::create_dialog {mytoplevel} {
toplevel $mytoplevel -class DialogWindow
variable mytoplevelref $mytoplevel
wm title $mytoplevel [_ "Find externals"]
wm geometry $mytoplevel 670x550
wm minsize $mytoplevel 230 360
wm transient $mytoplevel
$mytoplevel configure -padx 10 -pady 5
if {$::windowingsystem eq "aqua"} {
$mytoplevel configure -menu $::dialog_menubar
}
frame $mytoplevel.searchbit
pack $mytoplevel.searchbit -side top -fill x
entry $mytoplevel.searchbit.entry -font 18 -relief sunken -highlightthickness 1 -highlightcolor blue
pack $mytoplevel.searchbit.entry -side left -padx 6 -fill x -expand true
bind $mytoplevel.searchbit.entry "::deken::initiate_search $mytoplevel"
bind $mytoplevel.searchbit.entry "::deken::update_searchbutton $mytoplevel"
focus $mytoplevel.searchbit.entry
frame $mytoplevel.warning
pack $mytoplevel.warning -side top -fill x
label $mytoplevel.warning.label -text "Only install externals uploaded by people you trust."
pack $mytoplevel.warning.label -side left -padx 6
frame $mytoplevel.status
pack $mytoplevel.status -side bottom -fill x
label $mytoplevel.status.label -textvariable ::deken::statustext
pack $mytoplevel.status.label -side left -padx 6
button $mytoplevel.searchbit.button -text [_ "Show all"] -default active -width 9 -command "::deken::initiate_search $mytoplevel"
pack $mytoplevel.searchbit.button -side right -padx 6 -pady 3
text $mytoplevel.results -takefocus 0 -cursor hand2 -height 100 -yscrollcommand "$mytoplevel.results.ys set"
scrollbar $mytoplevel.results.ys -orient vertical -command "$mytoplevel.results yview"
pack $mytoplevel.results.ys -side right -fill y
pack $mytoplevel.results -side left -padx 6 -pady 3 -fill both -expand true
}
proc ::deken::initiate_search {mytoplevel} {
# let the user know what we're doing
::deken::clearpost
::deken::post "Searching for externals..."
# make the ajax call
if { [ catch {
set results [::deken::search_for [$mytoplevel.searchbit.entry get]]
} stdout ] } {
puts "online?"
puts "$stdout"
::deken::status "Unable to perform search. Are you online?"
} else {
# delete all text in the results
::deken::clearpost
if {[llength $results] != 0} {
set counter 0
# build the list UI of results
foreach r $results {
::deken::show_result $mytoplevel $counter $r 1
incr counter
}
foreach r $results {
::deken::show_result $mytoplevel $counter $r 0
incr counter
}
} else {
::deken::post "No matching externals found. Try using the full name e.g. 'freeverb'."
}
}}
# display a single found entry
proc ::deken::show_result {mytoplevel counter result showmatches} {
foreach {title cmd match comment status} $result {break}
set tag ch$counter
#if { [ ($match) ] } { set matchtag archmatch } { set matchtag noarchmatch }
set matchtag [expr $match?"archmatch":"noarchmatch" ]
if {($match == $showmatches)} {
set comment [string map {"\n" "\n\t"} $comment]
::deken::post "$title\n\t$comment\n" [list $tag $matchtag]
::deken::highlightable_posttag $tag
::deken::bind_posttag $tag "+::deken::status $status"
# have to decode the URL here because otherwise percent signs cause tcl to bug out - not sure why - scripting languages...
#::deken::bind_posttag $tag <1> [list ::deken::clicked_link $mytoplevel [urldecode $URL] $filename]
::deken::bind_posttag $tag <1> "$cmd"
}
}
# handle a clicked link
proc ::deken::clicked_link {URL filename} {
## make sure that the destination path exists
if { "$::deken::installpath" == "" } { set ::deken::installpath [ ::deken::get_writable_dir $::sys_staticpath ] }
if { "$::deken::installpath" == "" } {
::deken::clearpost
::deken::post "No writeable directory found in:" warn
foreach p $::sys_staticpath { ::deken::post "\t- $p\n" warn }
::deken::post "Cannot download/install libraries!\n" warn
} {
set fullpkgfile "$::deken::installpath/$filename"
::deken::clearpost
::deken::post "Commencing downloading of:\n$URL\nInto $::deken::installpath..."
::deken::download_file $URL $fullpkgfile
set PWD [ pwd ]
cd $::deken::installpath
set success 1
if { [ string match *.zip $fullpkgfile ] } then {
if { [ catch { exec unzip -uo $fullpkgfile } stdout ] } {
puts $stdout
set success 0
}
} elseif { [ string match *.tar.gz $fullpkgfile ]
|| [ string match *.tgz $fullpkgfile ]
} then {
if { [ catch { exec tar xzf $fullpkgfile } stdout ] } {
puts $stdout
set success 0
}
}
cd $PWD
if { $success > 0 } {
::deken::post "Successfully unzipped $filename into $::deken::installpath.\n"
} else {
# Open both the fullpkgfile folder and the zipfile itself
# NOTE: in tcl 8.6 it should be possible to use the zlib interface to actually do the unzip
::deken::post "Unable to extract package automatically." warn
::deken::post "Please perform the following steps manually:"
::deken::post "1. Unzip $fullpkgfile."
pd_menucommands::menu_openfile $fullpkgfile
::deken::post "2. Copy the contents into $::deken::installpath.\n"
pd_menucommands::menu_openfile $::deken::installpath
}
}
}
# download a file to a location
# http://wiki.tcl.tk/15303
proc ::deken::download_file {URL outputfilename} {
set f [open $outputfilename w]
set status ""
set errorstatus ""
fconfigure $f -translation binary
set httpresult [http::geturl $URL -binary true -progress "::deken::download_progress" -channel $f]
set status [::http::status $httpresult]
set errorstatus [::http::error $httpresult]
flush $f
close $f
http::cleanup $httpresult
return [list $status $errorstatus ]
}
# print the download progress to the results window
proc ::deken::download_progress {token total current} {
if { $total > 0 } {
variable mytoplevelref
set computed [expr {round(100 * (1.0 * $current / $total))}]
::deken::post "= $computed%"
}
}
# parse a deken-packagefilename into it's components: [-v-]?{()}-externals.zip
# return: list [list ...]
proc ::deken::parse_filename {filename} {
set pkgname $filename
set archs [list]
set version ""
if { [ regexp {(.*)-externals\..*} $filename _ basename] } {
set pkgname $basename
# basename [-v-]?{()}
## strip off the archs
set baselist [split $basename () ]
# get pkgname + version
set pkgver [lindex $baselist 0]
if { ! [ regexp "(.*)-(.*)-" $pkgver _ pkgname version ] } {
set pkgname $pkgver
set $version ""
}
# get archs
foreach {a _} [lreplace $baselist 0 0] { lappend archs $a }
}
return [list $pkgname $version $archs]
}
# test for platform match with our current platform
proc ::deken::architecture_match {archs} {
# if there are no architecture sections this must be arch-independent
if { ! [llength $archs] } { return 1}
# check each architecture in our list against the current one
foreach arch $archs {
if { [ regexp -- {(.*)-(.*)-(.*)} $arch _ os machine bits ] } {
if { "${os}" eq "$::deken::platform(os)" &&
"${bits}" eq "$::deken::platform(bits)"
} {
## so OS and word size match
## check whether the CPU matches as well
if { "${machine}" eq "$::deken::platform(machine)" } {return 1}
## not exactly; see whether it is in the list of compat CPUs
if {[llength [array names ::deken::architecture_substitutes -exact $::deken::platform(machine)]]} {
foreach cpu $::deken::architecture_substitutes($::deken::platform(machine)) {
if { "${machine}" eq "${cpu}" } {return 1}
}
}
}
}
}
return 0
}
proc ::deken::search_for {term} {
::deken::status "searching for '$term'"
set result [list]
foreach searcher $::deken::backends {
set result [concat $result [ $searcher $term ] ]
}
return $result
}
# create an entry for our search in the "help" menu
set mymenu .menubar.help
if {$::windowingsystem eq "aqua"} {
set inserthere 3
} else {
set inserthere 4
}
$mymenu insert $inserthere separator
$mymenu insert $inserthere command -label [_ "Find externals"] -command {::deken::open_searchui .externals_searchui}
# bind all <$::modifier-Key-s> {::deken::open_helpbrowser .helpbrowser2}
# http://rosettacode.org/wiki/URL_decoding#Tcl
proc urldecode {str} {
set specialMap {"[" "%5B" "]" "%5D"}
set seqRE {%([0-9a-fA-F]{2})}
set replacement {[format "%c" [scan "\1" "%2x"]]}
set modStr [regsub -all $seqRE [string map $specialMap $str] $replacement]
return [encoding convertfrom utf-8 [subst -nobackslash -novariable $modStr]]
}
# ####################################################################
# search backends
# ####################################################################
## API draft
# each backend is implemented via a single proc
## that takes a single argument "term", the term to search fo
## an empty term indicates "search for all"
# the backend then returns a list of results
## each result is a list of the following elements:
##
## title: the primary name to display
## (the user will select the element by this name)
## e.g. "frobscottle-1.10 (Linux/amd64)"
## cmd : a command that will install the selected library
## e.g. "[list ::deken::clicked_link http://bfg.org/frobscottle-1.10.zip frobscottle-1.10.zip]"
## match: an integer indicating whether this entry is actually usable
## on this host (1) or not (0)
## comment: secondary line to display
## e.g. "uploaded by the BFG in 1982"
## status: line to display in the status-line
## e.g. "http://bfg.org/frobscottle-1.10.zip"
# note on sorting:
## the results ought to be sorted with most up-to-date first
## (filtering based on architecture-matches should be ignored when sorting!)
# note on helper-functions:
## you can put whatever you like into , even your own proc
# registration
## to register a new search function, call `::deken::register $myfun`
# namespace
## you are welcome to use the ::deken::search:: namespace
## ####################################################################
## searching puredata.info
proc ::deken::search::puredata.info {term} {
set searchresults [list]
set token [http::geturl "http://deken.puredata.info/search?name=$term"]
set contents [http::data $token]
set splitCont [split $contents "\n"]
# loop through the resulting tab-delimited table
foreach ele $splitCont {
set ele [ string trim $ele ]
if { "" ne $ele } {
set sele [ split $ele "\t" ]
set name [ string trim [ lindex $sele 0 ]]
set URL [ string trim [ lindex $sele 1 ]]
set creator [ string trim [ lindex $sele 2 ]]
set date [regsub -all {[TZ]} [ string trim [ lindex $sele 3 ] ] { }]
set decURL [urldecode $URL]
set filename [ file tail $URL ]
set cmd [list ::deken::clicked_link $decURL $filename]
set pkgverarch [ ::deken::parse_filename $filename ]
set match [::deken::architecture_match [lindex $pkgverarch 2] ]
set comment "Uploaded by $creator @ $date"
set status $URL
set sortname [lindex $pkgverarch 0]--[lindex $pkgverarch 1]--$date
set res [list $name $cmd $match $comment $status $filename]
lappend searchresults $res
}
}
http::cleanup $token
return [lsort -dictionary -decreasing -index 5 $searchresults ]
}
## ####################################################################
## searching apt (if available)
namespace eval ::deken::apt {
namespace export search
namespace export install
variable distribution
}
if { [ catch { exec apt-cache -v } _ ] } { } {
if { [ catch { exec lsb_release -si } ::deken::apt::distribution ] } { unset ::deken::apt::distribution }
}
proc ::deken::apt::search {name} {
set result []
if { [ catch { exec apt-cache madison } _ ] } {
::deken::post "Unable to run 'apt-cache madison'" error
} {
set name [ string tolower $name ]
if { "$name" eq "gem" } {
set searchname $name
} elseif { "$name" eq "" } {
set searchname "^pd-.*"
} else {
set searchname "^pd-${name}.*"
}
array unset pkgs
array set pkgs {}
set io [ open "|apt-cache madison $searchname" r ]
while { [ gets $io line ] >= 0 } {
#puts $line
set llin [ split "$line" "|" ]
set pkgname [ string trim [ lindex $llin 0 ] ]
#if { $pkgname ne $searchname } { continue }
set ver_ [ string trim [ lindex $llin 1 ] ]
set info_ [ string trim [ lindex $llin 2 ] ]
if { "Packages" eq [ lindex $info_ end ] } {
set suite [ lindex $info_ 1 ]
set arch [ lindex $info_ 2 ]
if { ! [ info exists pkgs($ver_) ] } {
set pkgs($ver_) [ list $pkgname $suite $arch ]
}
}
}
foreach {v inf} [ array get pkgs ] {
set pkgname [ lindex $inf 0 ]
set suite [ lindex $inf 1 ]
set arch [ lindex $inf 2 ]
set name $pkgname/$v
set cmd "::deken::apt::install ${pkgname}=$v"
set match 1
set comment "Provided by ${::deken::apt::distribution} (${suite})"
set status "${pkgname}_${v}_${arch}.deb"
lappend result [list $name $cmd $match $comment $status]
}
}
return [lsort -dictionary -decreasing -index 1 $result ]
}
proc ::deken::apt::install {pkg} {
if { [ catch { exec which gksudo } gsudo ] } {
::deken::post "Please install 'gksudo', if you want to install system packages via deken..." error
} {
::deken::clearpost
set prog "apt-get install -y --show-progress ${pkg}"
# for whatever reasons, we cannot have 'deken' as the description
# (it will always show $prog instead)
set desc deken::apt
set cmdline "$gsudo -D $desc -- $prog"
#puts $cmdline
set io [ open "|${cmdline}" ]
while { [ gets $io line ] >= 0 } {
::deken::post "apt: $line"
}
if { [ catch { close $io } ret ] } {
::deken::post "apt::install failed to install $pkg" error
::deken::post "\tDid you provide the correct password and/or" error
::deken::post "\tis the apt database locked by another process?" error
#puts stderr "::deken::apt::install ${options}"
}
}
}
# only add this backend, if we are actually running Debian or a derivative
if { [ info exists ::deken::apt::distribution ] } {
::deken::register ::deken::apt::search
}
::deken::register ::deken::search::puredata.info
deken-0.1/deken.gif 0000664 0000000 0000000 00005230073 12556743566 0014252 0 ustar 00root root 0000000 0000000 GIF89apG م怳|uڂzz恭ywnrvlн¼qsޏrnk^tfibx߭ᙙeeǁbrqemkkxǶH'ٱpy(6Tϴ7&657)'(GIX @n$ƹϷǢtD[xvns'0ȘhueZhۮ0%hiw(ɷ&PmQ5*IQH:F:IeVJe7.NNmzɖᬗ÷qP4rJrfV2Ms|[4WcXsbP|ǽ膭v{tzNҴw|Owe=65feL~6jv~jXrd|셸Ýx{{z$>|
߳Z(vJ5l.!o-`Pegw1<:VU)2*PP13J5MHkNpo0/kUr,)/N&֗k.-H3^p,H`2!NETSCAPE2.0 !2 , p (p`p8 YŃ:LlZ
z2A
V\F,Qf`ɖ,9f*jdO%a S&I.ӑ4^It'¯~H&į.{Dq-Q>%SU&ŨlP)e;5U?æhDvuGK
6[nK4X3CL]\5ΧBG=1e*2:mAo\qq>6.Lo!FyR|lN
fkGv;3Rid7Uc%b4w MM]guYH$Jn]g\Faƕ^.VdWXB^͉NgULJ4CbZ48&B%o59FSReHtSJcWC'6ՕY&Efn9$`9XG7a&zU:'\ZEdEtgzTJREz S-変"v rej{(*A#T_xf/+-
@Hn*q֢6j#":waW2DC`۶5+rDLkߥT@Dt+mC!/AnK:0xSFC,< |ezhp[