mirror of
https://github.com/j-a-n/raspberrymatic-addon-rmupdate.git
synced 2023-10-10 13:37:40 +02:00
devel
This commit is contained in:
parent
9c3156f0f6
commit
63580ae33f
@ -17,14 +17,19 @@
|
||||
#
|
||||
|
||||
namespace eval rmupdate {
|
||||
variable addon_dir "/usr/local/addons/raspmatic-update"
|
||||
variable tmp_dir "/usr/local/addons/raspmatic-update/tmp"
|
||||
variable mnt_cur "/usr/local/addons/raspmatic-update/mnt_cur"
|
||||
variable mnt_new "/usr/local/addons/raspmatic-update/mnt_new"
|
||||
variable release_url "https://github.com/jens-maus/RaspberryMatic/releases"
|
||||
variable addon_dir "/usr/local/addons/rmupdate"
|
||||
variable img_dir "/usr/local/addons/rmupdate/var/img"
|
||||
variable mnt_cur "/usr/local/addons/rmupdate/var/mnt_cur"
|
||||
variable mnt_new "/usr/local/addons/rmupdate/var/mnt_new"
|
||||
variable sys_dev "/dev/mmcblk0"
|
||||
variable loop_dev "/dev/loop7"
|
||||
}
|
||||
|
||||
proc ::rmupdate::compare_versions {a b} {
|
||||
return [package vcompare $a $b]
|
||||
}
|
||||
|
||||
proc ::rmupdate::write_log {str} {
|
||||
puts stderr $str
|
||||
#set fd [open "/tmp/rmupdate.log" "a"]
|
||||
@ -33,7 +38,7 @@ proc ::rmupdate::write_log {str} {
|
||||
}
|
||||
|
||||
proc ::rmupdate::version {} {
|
||||
variable version_file
|
||||
variable addon_dir
|
||||
set fp [open "${addon_dir}/VERSION" r]
|
||||
set data [read $fp]
|
||||
close $fp
|
||||
@ -153,35 +158,18 @@ proc ::rmupdate::update_filesystems {image} {
|
||||
}
|
||||
}
|
||||
|
||||
proc ::rmupdate::get_latest_firmware_download_url {} {
|
||||
set data [exec wget "https://github.com/jens-maus/RaspberryMatic/releases/latest" --no-check-certificate -q -O-]
|
||||
foreach d [split $data "\n"] {
|
||||
set href ""
|
||||
regexp {<\s*a\s+href\s*=\s*"([^"]+/releases/download/[^"]+.zip)"} $d match href
|
||||
if { [info exists href] && $href != ""} {
|
||||
return "https://github.com${href}"
|
||||
}
|
||||
}
|
||||
error "Failed to get latest firmware download url"
|
||||
}
|
||||
|
||||
proc ::rmupdate::download_latest_firmware {} {
|
||||
variable tmp_dir
|
||||
|
||||
set download_url [get_latest_firmware_download_url]
|
||||
write_log "Downloading latest firmware from ${download_url}."
|
||||
regexp {/([^/]+)$} $download_url match archive_file
|
||||
set archive_file "${tmp_dir}/${archive_file}"
|
||||
file mkdir $tmp_dir
|
||||
exec wget "${download_url}" --no-check-certificate -q --output-document=$archive_file
|
||||
return $archive_file
|
||||
}
|
||||
|
||||
proc ::rmupdate::get_latest_firmware_version {} {
|
||||
set download_url [get_latest_firmware_download_url]
|
||||
regexp {\-([\d\.]+).zip$} $download_url match latest_version
|
||||
return $latest_version
|
||||
}
|
||||
#proc ::rmupdate::is_firmware_up_to_date {} {
|
||||
# set latest_version [get_latest_firmware_version]
|
||||
# write_log "Latest firmware version: ${latest_version}"
|
||||
#
|
||||
# set current_version [get_current_firmware_version]
|
||||
# write_log "Current firmware version: ${current_version}"
|
||||
#
|
||||
# if {[compare_versions $current_version $latest_version] >= 0} {
|
||||
# return 1
|
||||
# }
|
||||
# return 0
|
||||
#}
|
||||
|
||||
proc ::rmupdate::get_current_firmware_version {} {
|
||||
set fp [open "/boot/VERSION" r]
|
||||
@ -191,32 +179,147 @@ proc ::rmupdate::get_current_firmware_version {} {
|
||||
return $current_version
|
||||
}
|
||||
|
||||
proc ::rmupdate::is_firmware_up_to_date {} {
|
||||
set latest_version [get_latest_firmware_version]
|
||||
write_log "Latest firmware version: ${latest_version}"
|
||||
|
||||
set current_version [get_current_firmware_version]
|
||||
write_log "Current firmware version: ${current_version}"
|
||||
|
||||
if {[string compare $current_version $latest_version] >= 0} {
|
||||
return 1
|
||||
proc ::rmupdate::get_available_firmware_downloads {} {
|
||||
variable release_url
|
||||
set download_urls [list]
|
||||
set data [exec wget "${release_url}" --no-check-certificate -q -O-]
|
||||
foreach d [split $data ">"] {
|
||||
set href ""
|
||||
regexp {<\s*a\s+href\s*=\s*"([^"]+/releases/download/[^"]+\.zip)"} $d match href
|
||||
if { [info exists href] && $href != ""} {
|
||||
lappend download_urls "https://github.com${href}"
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return $download_urls
|
||||
}
|
||||
|
||||
rmupdate::download_latest_firmware
|
||||
proc ::rmupdate::get_latest_firmware_version {} {
|
||||
set versions [list]
|
||||
foreach e [get_available_firmware_downloads] {
|
||||
lappend versions [get_version_from_filename $e]
|
||||
}
|
||||
set versions [lsort -decreasing -command compare_versions $versions]
|
||||
return [lindex $versions 0]
|
||||
}
|
||||
|
||||
proc ::rmupdate::download_firmware {version} {
|
||||
variable img_dir
|
||||
set image_file "${img_dir}/RaspberryMatic-${version}.img"
|
||||
set download_url ""
|
||||
foreach e [get_available_firmware_downloads] {
|
||||
set v [get_version_from_filename $e]
|
||||
if {$v == $version} {
|
||||
set download_url $e
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$download_url == ""} {
|
||||
error "Failed to get url for firmware ${version}"
|
||||
}
|
||||
write_log "Downloading firmware from ${download_url}."
|
||||
regexp {/([^/]+)$} $download_url match archive_file
|
||||
set archive_file "${img_dir}/${archive_file}"
|
||||
file mkdir $img_dir
|
||||
exec wget "${download_url}" --no-check-certificate -q --output-document=$archive_file
|
||||
|
||||
write_log "Extracting firmware ${archive_file}."
|
||||
set data [exec unzip -ql "${archive_file}"]
|
||||
set img_file ""
|
||||
foreach d [split $data "\n"] {
|
||||
regexp {\s+(\S+\.img)\s*$} $d match img_file
|
||||
if { $img_file != "" } {
|
||||
break
|
||||
}
|
||||
}
|
||||
if { $img_file == "" } {
|
||||
error "Failed to extract image from archive."
|
||||
}
|
||||
exec unzip "${archive_file}" "${img_file}" -o -d "${img_dir}"
|
||||
set img_file "${img_dir}/${img_file}"
|
||||
puts "${img_file} ${image_file}"
|
||||
if {$img_file != $image_file} {
|
||||
file rename $img_file $image_file
|
||||
}
|
||||
file delete $archive_file
|
||||
return $image_file
|
||||
}
|
||||
|
||||
proc ::rmupdate::get_available_firmware_images {} {
|
||||
variable img_dir
|
||||
file mkdir $img_dir
|
||||
return [glob -nocomplain "${img_dir}/*.img"]
|
||||
}
|
||||
|
||||
proc ::rmupdate::get_version_from_filename {filename} {
|
||||
regexp {\-([\d\.]+)\.[^\.]+$} $filename match version
|
||||
return $version
|
||||
}
|
||||
|
||||
proc ::rmupdate::get_firmware_info {} {
|
||||
set current [get_current_firmware_version]
|
||||
set versions [list $current]
|
||||
foreach e [get_available_firmware_downloads] {
|
||||
set version [get_version_from_filename $e]
|
||||
set downloads($version) $e
|
||||
if {[lsearch $versions $version] == -1} {
|
||||
lappend versions $version
|
||||
}
|
||||
}
|
||||
foreach e [get_available_firmware_images] {
|
||||
set version [get_version_from_filename $e]
|
||||
set images($version) $e
|
||||
if {[lsearch $versions $version] == -1} {
|
||||
lappend versions $version
|
||||
}
|
||||
}
|
||||
set versions [lsort -decreasing -command compare_versions $versions]
|
||||
|
||||
set json "\["
|
||||
set latest "true"
|
||||
foreach v $versions {
|
||||
set installed "false"
|
||||
if {$v == $current} {
|
||||
set installed "true"
|
||||
}
|
||||
set image ""
|
||||
catch { set image $images($v) }
|
||||
set url ""
|
||||
catch { set url $downloads($v) }
|
||||
append json "\{\"version\":\"${v}\",\"installed\":${installed},\"latest\":${latest}\,\"url\":\"${url}\",\"image\":\"${image}\"\},"
|
||||
set latest "false"
|
||||
}
|
||||
if {[llength versions] > 0} {
|
||||
set json [string range $json 0 end-1]
|
||||
}
|
||||
append json "\]"
|
||||
return $json
|
||||
}
|
||||
|
||||
proc ::rmupdate::install_firmware_version {version} {
|
||||
set firmware_image ""
|
||||
#foreach e [get_available_firmware_images] {
|
||||
# set v [get_version_from_filename $e]
|
||||
# if {$v == $version} {
|
||||
# set firmware_image $e
|
||||
# break
|
||||
# }
|
||||
#}
|
||||
if {$firmware_image == ""} {
|
||||
download_firmware $version
|
||||
}
|
||||
}
|
||||
|
||||
#puts [rmupdate::get_latest_firmware_version]
|
||||
#puts [rmupdate::get_firmware_info]
|
||||
#puts [rmupdate::get_available_firmware_images]
|
||||
#puts [rmupdate::get_available_firmware_downloads]
|
||||
#rmupdate::download_latest_firmware
|
||||
#puts [rmupdate::is_firmware_up_to_date]
|
||||
|
||||
#puts [rmupdate::get_latest_firmware_download_url]
|
||||
|
||||
#rmupdate::check_sizes "/usr/local/addons/raspmatic-update/tmp/RaspberryMatic-2.27.7.20170316.img"
|
||||
|
||||
#set res [rmupdate::get_partion_start_and_size "/dev/mmcblk0" 1]
|
||||
|
||||
#rmupdate::mount_image_partition "/usr/local/addons/raspmatic-update/tmp/RaspberryMatic-2.27.7.20170316.img" 1 $rmupdate::mnt_new
|
||||
#rmupdate::umount $rmupdate::mnt_new
|
||||
|
||||
#rmupdate::mount_system_partition "/boot" $rmupdate::mnt_cur
|
||||
#rmupdate::umount $rmupdate::mnt_cur
|
||||
|
||||
|
66
addon/rmupdate.tcl
Normal file
66
addon/rmupdate.tcl
Normal file
@ -0,0 +1,66 @@
|
||||
#!/bin/tclsh
|
||||
|
||||
# RaspMatic update addon
|
||||
#
|
||||
# Copyright (C) 2017 Jan Schneider <oss@janschneider.net>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
source /usr/local/addons/rmupdate/lib/rmupdate.tcl
|
||||
|
||||
proc usage {} {
|
||||
global argv0
|
||||
puts stderr ""
|
||||
puts stderr "usage: ${argv0} <command>"
|
||||
puts stderr ""
|
||||
puts stderr "possible commands:"
|
||||
puts stderr " show_current : show current firmware version"
|
||||
puts stderr " show_latest : show latest available firmware version"
|
||||
puts stderr " install_latest : install latest available firmware version"
|
||||
puts stderr " install <version> : install firmware VERSION"
|
||||
}
|
||||
|
||||
proc main {} {
|
||||
global argc
|
||||
global argv
|
||||
|
||||
set cmd [string tolower [lindex $argv 0]]
|
||||
|
||||
if {$cmd == "show_current"} {
|
||||
puts [rmupdate::get_current_firmware_version]
|
||||
} elsif {$cmd == "show_latest"} {
|
||||
puts [rmupdate::get_latest_firmware_version]
|
||||
} elsif {$cmd == "install_latest"} {
|
||||
rmupdate::install_firmware_version [rmupdate::get_latest_firmware_version]
|
||||
} elsif {$cmd == "install"} {
|
||||
if {$argc < 2} {
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
rmupdate::install_firmware_version [lindex $argv 1]
|
||||
} else {
|
||||
usage
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if { [ catch {
|
||||
main
|
||||
} err ] } {
|
||||
puts stderr "ERROR: $err"
|
||||
exit 1
|
||||
}
|
||||
exit 0
|
||||
|
||||
|
@ -30,8 +30,158 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
<title>RaspberryMatic Update Addon</title>
|
||||
<script>
|
||||
var message_timer_id = null;
|
||||
|
||||
function display_message(type, html, millis) {
|
||||
clear_message();
|
||||
$('#message').html(html);
|
||||
$('#message').attr('class', 'ui ' + type + ' message visible');
|
||||
$('#message-edit-bridge').html(html);
|
||||
$('#message-edit-bridge').attr('class', 'ui ' + type + ' message visible');
|
||||
message_timer_id = setTimeout(clear_message, millis);
|
||||
}
|
||||
|
||||
function clear_message() {
|
||||
if (message_timer_id != null) {
|
||||
clearTimeout(message_timer_id);
|
||||
}
|
||||
message_timer_id = null;
|
||||
$('#message').html('');
|
||||
$('#message').attr('class', 'ui message hidden');
|
||||
$('#message-edit-bridge').html('');
|
||||
$('#message-edit-bridge').attr('class', 'ui message hidden');
|
||||
}
|
||||
|
||||
function rest(method, path, data, success_callback, error_callback) {
|
||||
if (!error_callback) {
|
||||
error_callback = function(xhr, ajaxOptions, thrownError) {
|
||||
console.error(xhr);
|
||||
err = thrownError;
|
||||
try {
|
||||
obj = JSON.parse(xhr.responseText);
|
||||
if (obj.error != null) {
|
||||
err = obj.error;
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
}
|
||||
display_message('error', 'An error occurred: ' + err, 60000);
|
||||
}
|
||||
}
|
||||
$.ajax({
|
||||
url: "rest.cgi?" + path,
|
||||
type: method,
|
||||
data: data,
|
||||
context: document.body,
|
||||
success: success_callback,
|
||||
error: error_callback
|
||||
});
|
||||
}
|
||||
|
||||
function install_firmware(version) {
|
||||
$('#modal-log').modal('show');
|
||||
//$('#log-content').append('Some text<br/>');
|
||||
//$('#modal-log').modal('refresh');
|
||||
//$('#modal-log').modal('hide');
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'rest.cgi?/install_firmware', true);
|
||||
xhr.send(null);
|
||||
var timer;
|
||||
timer = window.setInterval(function() {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||
window.clearTimeout(timer);
|
||||
//$('body').append('done <br />');
|
||||
}
|
||||
//$('body').append('state: ' + xhr.readyState + '<br />');
|
||||
console.log(xhr.responseText);
|
||||
$('#log-content').append(xhr.responseText + '<br/>');
|
||||
//$('body').append('data: ' + xhr.responseText + '<br />');
|
||||
}, 1000);
|
||||
/*
|
||||
var last_response_len = false;
|
||||
$.ajax('rest.cgi?/install_firmware', {
|
||||
xhrFields: {
|
||||
onprogress: function(e) {
|
||||
var this_response, response = e.currentTarget.response;
|
||||
if(last_response_len === false) {
|
||||
this_response = response;
|
||||
last_response_len = response.length;
|
||||
}
|
||||
else {
|
||||
this_response = response.substring(last_response_len);
|
||||
last_response_len = response.length;
|
||||
}
|
||||
console.log(this_response);
|
||||
}
|
||||
}
|
||||
}).done(function(data) {
|
||||
console.log('Complete response = ' + data);
|
||||
}).fail(function(data) {
|
||||
console.log('Error: ', data);
|
||||
});
|
||||
console.log('Request Sent');
|
||||
*/
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
rest("GET", "/version", null, function(version) {
|
||||
document.title = document.title + " " + version;
|
||||
});
|
||||
rest("GET", "/get_firmware_info", null, function(data) {
|
||||
$('#firmware_info tbody').empty();
|
||||
data.forEach(function(fw) {
|
||||
var disabled = (fw.image || fw.url ? '' : 'disabled');
|
||||
var binstall = $('<button class="ui green basic '+disabled+' button">').attr('data-version', fw.version).text('install');
|
||||
binstall.click(function() {
|
||||
install_firmware(this.getAttribute('data-version'));
|
||||
});
|
||||
var latest = (fw.latest ? 'checked=""' : '')
|
||||
var installed = (fw.installed ? 'checked=""' : '')
|
||||
var available = (fw.url ? 'checked=""' : '')
|
||||
var downloaded = (fw.image ? 'checked=""' : '')
|
||||
$("#firmware_info tbody").append($('<tr>').append(
|
||||
$('<td>').text(fw.version),
|
||||
$('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+latest+'>'),$('<label></label>'))),
|
||||
$('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+installed+'>'),$('<label></label>'))),
|
||||
$('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+available+'>'),$('<label></label>'))),
|
||||
$('<td class="center aligned">').append($('<div class="ui disabled checkbox">').append($('<input type="checkbox" disabled="disabled" '+downloaded+'>'),$('<label></label>'))),
|
||||
$('<td class="center aligned">').append(binstall)
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div style="padding-top: 5vw" class="ui container">
|
||||
<h1 class="ui header">RaspberryMatic Update</h1>
|
||||
<div id="message" class="ui message hidden">
|
||||
</div>
|
||||
<h2 class="ui dividing header">Firmwares</h2>
|
||||
<table id="firmware_info" class="ui celled stackable table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th class="center aligned">Latest</th>
|
||||
<th class="center aligned">Installed</th>
|
||||
<th class="center aligned">Available</th>
|
||||
<th class="center aligned">Downloaded</th>
|
||||
<th class="center aligned">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="modal-log" class="ui modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="header">
|
||||
Progress
|
||||
</div>
|
||||
<div id="log-content" class="content">
|
||||
Line 1
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -45,7 +45,28 @@ proc process {} {
|
||||
|
||||
if {[lindex $path 1] == "version"} {
|
||||
return "\"[rmupdate::version]\""
|
||||
} elseif {[lindex $path 1] == "xy"} {
|
||||
} elseif {[lindex $path 1] == "get_firmware_info"} {
|
||||
return [rmupdate::get_firmware_info]
|
||||
} elseif {[lindex $path 1] == "install_firmware"} {
|
||||
fconfigure stdout -buffering none
|
||||
#puts "Content-Type: application/octet-stream"
|
||||
puts "Content-Type: text/html; charset=utf-8"
|
||||
puts "Status: 200 OK";
|
||||
puts ""
|
||||
flush stdout
|
||||
after 1000
|
||||
puts "Line 1\n"
|
||||
flush stdout
|
||||
after 1000
|
||||
puts "Line 2\n"
|
||||
flush stdout
|
||||
after 1000
|
||||
puts "Line 3\n"
|
||||
flush stdout
|
||||
after 1000
|
||||
puts "Line 4\n"
|
||||
flush stdout
|
||||
return ""
|
||||
}
|
||||
}
|
||||
error "invalid request" "Not found" 404
|
||||
@ -61,7 +82,7 @@ if [catch {process} result] {
|
||||
puts ""
|
||||
set result [json_string $result]
|
||||
puts -nonewline "\{\"error\":\"${result}\"\}"
|
||||
} else {
|
||||
} elseif {$result != ""} {
|
||||
puts "Content-Type: application/json"
|
||||
puts "Status: 200 OK";
|
||||
puts ""
|
||||
|
Loading…
Reference in New Issue
Block a user