[113397] users/jmr

jmr at macports.org jmr at macports.org
Fri Nov 15 05:23:48 PST 2013


Revision: 113397
          https://trac.macports.org/changeset/113397
Author:   jmr at macports.org
Date:     2013-11-15 05:23:48 -0800 (Fri, 15 Nov 2013)
Log Message:
-----------
WIP - repackage client side of gsoc11-statistics as a port

Added Paths:
-----------
    users/jmr/mpstats/
    users/jmr/mpstats/mpstats.conf
    users/jmr/mpstats/mpstats.tcl
    users/jmr/mpstats/port/
    users/jmr/mpstats/port/Portfile
    users/jmr/mpstats/setupstats.sh

Added: users/jmr/mpstats/mpstats.conf
===================================================================
--- users/jmr/mpstats/mpstats.conf	                        (rev 0)
+++ users/jmr/mpstats/mpstats.conf	2013-11-15 13:23:48 UTC (rev 113397)
@@ -0,0 +1,8 @@
+# $Id$
+# configuration for mpstats
+
+# Where to submit usage data
+stats_url       localhost
+
+# Unique identifier for usage statistics
+stats_id        @STATS_UUID@


Property changes on: users/jmr/mpstats/mpstats.conf
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: users/jmr/mpstats/mpstats.tcl
===================================================================
--- users/jmr/mpstats/mpstats.tcl	                        (rev 0)
+++ users/jmr/mpstats/mpstats.tcl	2013-11-15 13:23:48 UTC (rev 113397)
@@ -0,0 +1,334 @@
+#!/usr/bin/tclsh
+# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
+# $Id$
+#
+# Copyright (c) 2011,2013 The MacPorts Project
+#
+# 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. Neither the name of The MacPorts Project nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "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 COPYRIGHT
+# OWNER OR CONTRIBUTORS 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.
+
+set VERSION 0.1
+set prefix /opt/local
+
+if {[catch {source ${prefix}/share/macports/Tcl/macports1.0/macports_fastload.tcl} result]} {
+    puts stderr "Error: $result"
+    exit 1
+}
+
+package require macports
+if {[catch {mportinit} result]} {
+    puts stderr "Error: $result"
+    exit 1
+}
+
+proc usage {} {
+    ui_msg "Usage: $::argv0 \[submit|show\]"
+}
+
+proc read_config {} {
+    global prefix stats_url stats_id
+    set stats_url localhost
+    set stats_id 123
+    set conf_path "${prefix}/etc/mpstats.conf"
+    if {[file isfile $conf_path]} {
+        set fd [open $conf_path r]
+        while {[gets $fd line] >= 0} {
+            set optname [lindex $line 0]
+            if {$optname eq "stats_url"} {
+                set stats_url [lindex $line 1]
+            } elseif {$optname eq "stats_id"} {
+                set stats_id [lindex $line 1]
+            }
+        }
+        close $fd
+    }
+}
+
+# extraction of gcc version
+proc getgccinfo {} {
+    # Find gcc in path
+    if {[catch {set gccpath [macports::binaryInPath "gcc"]}] != 0} {
+        # Failed
+        ui_msg "$::errorInfo"
+        return none
+    }
+
+    # Call gcc -v - Note that output will be on stderr not stdout
+    # This succeeds if catch returns nonzero
+    if { [catch { exec $gccpath -v } gccinfo] == 0} {
+        # Failed
+        ui_msg "$::errorInfo"
+        return none
+    }
+
+    # Extract version
+    if {[regexp {gcc version ([0-9.]+)} $gccinfo - gcc_v] == 1} {
+        # Set gcc version
+        return $gcc_v
+    } else {
+        ui_warn "gcc exists but could not read version information"
+        return none
+    }
+}
+
+###### JSON Encoding helper procs ######
+
+# Return JSON encoding of a flat "key":"value" dictionary
+proc json_encode_dict { data } {
+    upvar 1 $data db
+
+    set size [dict size $db]
+    set i 1
+
+    # Initialize the JSON string string
+    set json "\{"
+
+    dict for {key values} $db {
+        set line "\"$key\":\"[dict get $db $key]\""
+
+        # Check if there are any subsequent items
+        if {$i < $size} {
+            set line "$line, "
+        } 
+
+        # Add line to the JSON string
+        set json "$json$line"
+
+        incr i
+    }
+
+    set json "$json\}"
+
+    return $json
+}
+
+# Encodes a list of strings as a JSON array
+proc json_encode_list { data } {    
+    set size [llength $data]
+    set i 1
+
+    set json "\["
+
+    foreach item $data {
+        set json "$json$data"
+
+        # Check if there are any subsequent items
+        if {$i < $size} {
+            set json "$json, "
+        }
+
+        incr i
+    }
+
+    set json "$json \]"
+
+    return $json
+}
+
+# Encode a port (from a portlist entry) as a JSON object
+proc json_encode_port { port_info } {
+    upvar 1 $port_info port
+
+    set first true
+
+    set json "\{"
+    foreach name [array names port] {
+
+        # Skip empty strings
+        if {$port($name) eq ""} {
+            continue
+        }
+
+        # Prepend a comma if this isn't the first item that has been processed
+        if {!$first} {
+            # Add a comma
+            set json "$json, "
+       } else {
+           set first false
+       }
+
+        # Format the entry as "name_string":"value"
+        set entry "\"$name\":\"$port($name)\"" 
+        set json "$json$entry"
+    }
+
+    set json "$json\}"
+
+    return $json
+}
+
+# Encode portlist as a JSON array of port objects
+proc json_encode_portlist { portlist } {
+    set json "\["
+    set first true
+
+    foreach i $portlist {
+        array set port $i
+
+        set encoded [json_encode_port port]
+
+        # Prepend a comma if this isn't the first item that has been processed
+        if {!$first} {
+            # Add a comma
+            set json "$json, "
+       } else {
+           set first false
+       }
+
+        # Append encoded json object
+        set json "$json$encoded"
+    }
+
+    set json "$json\]"
+
+    return $json
+}
+
+# Top level container for os and port data
+# Returns a JSON Object with three  
+proc json_encode_stats {id os_dict ports_dict} {
+    upvar 1 $os_dict os
+    upvar 1 $ports_dict ports
+
+    set os_json [json_encode_dict os]
+    set active_ports_json [json_encode_portlist [dict get $ports "active"]]
+    set inactive_ports_json [json_encode_portlist [dict get $ports "inactive"]]
+
+    set json "\{"
+    set json "$json \"id\":\"$id\","
+    set json "$json \"os\":$os_json,"
+    set json "$json \"active_ports\":$active_ports_json,"
+    set json "$json \"inactive_ports\":$inactive_ports_json"
+    set json "$json\}"
+
+    return $json
+}
+
+proc split_variants {variants} {
+    set result {}
+    set l [regexp -all -inline -- {([-+])([[:alpha:]_]+[\w\.]*)} $variants]
+    foreach { match sign variant } $l {
+        lappend result $variant $sign
+    }
+    return $result
+}
+
+proc get_installed_ports {active} {
+    set ilist {}
+    if { [catch {set ilist [registry::installed]} result] } {
+        if {$result != "Registry error: No ports registered as installed."} {
+            ui_debug "$::errorInfo"
+            return -code error "registry::installed failed: $result"
+        }
+    }
+
+    set results {}
+    foreach i $ilist {
+        set iactive [lindex $i 4]
+
+        if {(${active} == "yes") == (${iactive} != 0)} {
+            set iname [lindex $i 0]
+            set iversion [lindex $i 1]
+            set irevision [lindex $i 2]
+            set ivariants [split_variants [lindex $i 3]]
+            lappend results [list name $iname version "${iversion}_${irevision}" variants $ivariants]
+        }
+    }
+
+    return $results
+}
+
+
+proc action_stats {subcommands} {
+    global stats_url stats_id
+
+    # Build dictionary of os information
+    dict set os macports_version [macports::version]
+    dict set os osx_version ${macports::macosx_version}
+    dict set os os_arch ${macports::os_arch} 
+    dict set os os_platform ${macports::os_platform}
+    dict set os build_arch ${macports::build_arch}
+    dict set os gcc_version [getgccinfo]
+    dict set os xcode_version ${macports::xcodeversion}
+
+    # Build dictionary of port information 
+    dict set ports active   [get_installed_ports yes]
+    dict set ports inactive [get_installed_ports no]
+
+    # If no subcommands are given (subcommands is empty) print out OS information
+    if {$subcommands eq ""} {
+        # Print information from os dictionary
+        dict for {key values} $os {
+            puts "$key: [dict get $os $key]"
+        }
+        return 0
+    }
+
+    # Make sure there aren't too many subcommands
+    if {[llength $subcommands] > 1} {
+        ui_error "Please select only one subcommand."
+        usage
+        return 1
+    }
+
+    if {![info exists stats_url]} {
+        ui_error "Configuration variable stats_url is not set"
+        return 1
+    }
+    if {![info exists stats_id]} {
+        ui_error "Configuration variable stats_id is not set"
+        return 1
+    }
+
+    set json [json_encode_stats $stats_id os ports]
+
+    # Get the subcommand
+    set cmd [lindex $subcommands 0]
+
+    switch $cmd {
+        submit {
+            ui_notice "Submitting to $stats_url"
+
+            if {[catch {curl post "submission\[data\]=$json" $stats_url} value]} {
+                ui_error "$::errorInfo"
+                return 1
+            }
+        }
+        show {
+            ui_notice "Would submit to $stats_url"
+            ui_msg "submission\[data\]=$json"
+        }
+        default {
+            puts "Unknown subcommand."
+            usage
+            return 1
+        }
+    }
+
+   return 0
+}
+
+read_config
+action_stats $argv


Property changes on: users/jmr/mpstats/mpstats.tcl
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: users/jmr/mpstats/port/Portfile
===================================================================
--- users/jmr/mpstats/port/Portfile	                        (rev 0)
+++ users/jmr/mpstats/port/Portfile	2013-11-15 13:23:48 UTC (rev 113397)
@@ -0,0 +1,45 @@
+# $Id$
+
+PortSystem          1.0
+
+name                mpstats
+version             0.1
+categories          sysutils
+license             BSD
+platforms           darwin
+supported_archs     noarch
+maintainers         nomaintainer
+description         submit statistics about your macports installation
+long_description \
+   This is a script and LaunchAgent which can run weekly to report \
+   information about your system and installed ports to a server, which \
+   publishes the aggregate statistics on the web.
+
+homepage            http://www.macports.org/
+master_sites        sourceforge:macports
+
+use_bzip2           yes
+checksums           rmd160 8fae2cb42569278cca5ea631a3805802de634971 \
+                    sha256 cd3f54df954e8091f01cf358af54090ac27bc8af8db259f42dee5875caf5a6ca
+
+configure {
+    reinplace "s|set prefix /opt/local|set prefix ${prefix}|" ${worksrcpath}/mpstats.tcl
+    reinplace "s|@STATS_UUID@|[exec uuidgen]|" ${worksrcpath}/mpstats.conf
+}
+build {}
+destroot {
+    xinstall ${worksrcpath}/mpstats.tcl ${destroot}${prefix}/bin/mpstats
+    xinstall -m 444 ${worksrcpath}/mpstats.conf ${destroot}${prefix}/etc/mpstats.conf.default
+    system -W ${worksrcpath} "DESTDIR=${destroot} ./setupstats.sh ${prefix}/bin/mpstats"
+}
+
+post-activate {
+    if {![file exists ${prefix}/etc/mpstats.conf]} {
+        copy ${prefix}/etc/mpstats.conf.default ${prefix}/etc/mpstats.conf
+    }
+}
+
+notes \
+"To enable automatic weekly reporting of data to the stats server,\
+run:
+launchctl load -w /Library/LaunchAgents/org.macports.stats.plist"


Property changes on: users/jmr/mpstats/port/Portfile
___________________________________________________________________
Added: svn:keywords
   + Id
Added: svn:eol-style
   + native

Added: users/jmr/mpstats/setupstats.sh
===================================================================
--- users/jmr/mpstats/setupstats.sh	                        (rev 0)
+++ users/jmr/mpstats/setupstats.sh	2013-11-15 13:23:48 UTC (rev 113397)
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Where the generated plist should be written
+PLIST=${DESTDIR}/Library/LaunchAgents/org.macports.stats.plist
+
+die () {
+    echo >&2 "$@"
+    exit 1
+}
+
+# Make sure exactly 2 arguments are provided
+[ "$#" -eq 1 ] || die "exactly one argument required"
+
+# $1 must be the path to the script launchd will execute
+SCRIPT=$1
+
+# Make sure the script argument is executable
+if [ ! -x "${DESTDIR}${SCRIPT}" ]; then
+   	die "$SCRIPT is not a valid executable"
+fi
+
+# Determine the day and time that launchd should run the script
+setup_times() {
+    # Get hardware uuid - Hardware UUID: UUID
+    huuid=`system_profiler SPHardwareDataType | grep "Hardware UUID"`
+    
+    # Strip out Hardware UUID:   
+    huuid=`echo $huuid | awk '/Hardware UUID/ {print $3;}'`
+    
+    # Strip out '-' characters
+    huuid=`echo $huuid | tr -d -`
+    
+    # Weekday is hardware uuid mod 7
+    weekday=`echo $huuid % 7 | bc`
+    
+    # Use current hours and minute
+    hour=`date '+%H'`
+    minute=`date '+%M'`
+}
+
+# Generate the launchd plist that executes 'port stats submit'
+# Outputs to the file $plist
+generate_plist() {
+    setup_times
+    mkdir -p `dirname $PLIST`
+	cat <<-EOF > $PLIST
+		<?xml version="1.0" encoding="UTF-8"?>
+        <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+        <plist version="1.0">
+         <dict>
+          <key>Label</key>
+          <string>org.macports.stats</string>
+          <key>ProgramArguments</key>
+          <array>
+             <string>$SCRIPT</string>
+             <string>submit</string>
+          </array>
+          <key>StartCalendarInterval</key>
+          <dict>
+            <key>Weekday</key>
+            <integer>$weekday</integer>
+            <key>Hour</key>
+            <integer>$hour</integer>
+            <key>Minute</key>
+            <integer>$minute</integer>
+          </dict>
+         </dict>
+        </plist>
+	EOF
+}
+
+# Generate and install the plist
+generate_plist


Property changes on: users/jmr/mpstats/setupstats.sh
___________________________________________________________________
Added: svn:executable
   + *
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macports-changes/attachments/20131115/ff92fa5f/attachment-0001.html>


More information about the macports-changes mailing list