<pre style='margin:0'>
Clemens Lang (neverpanic) pushed a commit to branch master
in repository macports-base.
</pre>
<p><a href="https://github.com/macports/macports-base/commit/f745b45435365bddc364a2d82bd7494cd20a92d0">https://github.com/macports/macports-base/commit/f745b45435365bddc364a2d82bd7494cd20a92d0</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit f745b45435365bddc364a2d82bd7494cd20a92d0
</span>Author: Clemens Lang <neverpanic@gmail.com>
AuthorDate: Thu Jul 25 14:06:02 2024 +0200
<span style='display:block; white-space:pre;color:#404040;'> snapshot: Add JSON import functionality
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This completes the export & import functionality. I changed the import
</span><span style='display:block; white-space:pre;color:#404040;'> to read from a file rather than stdin. For exporting, writing to stdout
</span><span style='display:block; white-space:pre;color:#404040;'> is useful because it allows the export to run as root, but the resulting
</span><span style='display:block; white-space:pre;color:#404040;'> file to be owned by the calling user, but for the import this isn't
</span><span style='display:block; white-space:pre;color:#404040;'> a concern.
</span>---
src/macports1.0/snapshot.tcl | 167 ++++++++++++++++++++++++++++++++++++++++++-
src/port/port.tcl | 2 +-
2 files changed, 167 insertions(+), 2 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/macports1.0/snapshot.tcl b/src/macports1.0/snapshot.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 4cf1028f9..ed4af75a0 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/macports1.0/snapshot.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/macports1.0/snapshot.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -32,6 +32,7 @@ package provide snapshot 1.0
</span>
package require macports 1.0
package require registry 1.0
<span style='display:block; white-space:pre;background:#e0ffe0;'>+package require json
</span> package require json::write
namespace eval snapshot {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -42,7 +43,7 @@ namespace eval snapshot {
</span> ui_msg " port snapshot --diff <snapshot-id> \[--all\]"
ui_msg " port snapshot --delete <snapshot-id>"
ui_msg " port snapshot --export <snapshot-id> >snapshot.json"
<span style='display:block; white-space:pre;background:#ffe0e0;'>- ui_msg " port snapshot --import <snapshot.json"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_msg " port snapshot --import snapshot.json"
</span> }
proc main {opts} {
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -195,6 +196,27 @@ namespace eval snapshot {
</span> puts [snapshot2json $snapshot]
}
"import" {
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ set filename [dict get $opts ports_snapshot_import]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set fp [open $filename r]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set contents [read $fp]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ close $fp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } on error {eMessage} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_error "Failed to read $filename: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set snapshot [import $contents $opts]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } on error {eMessage} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_error "Import failed: $eMessage"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_msg "Snapshot successfully imported with ID [$snapshot id]."
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_msg "To restore this snapshot now, run\n\tsudo port restore --snapshot-id [$snapshot id]"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0
</span> }
default {
print_usage
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -278,6 +300,149 @@ namespace eval snapshot {
</span> return $res
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc _last_insert_rowid {con} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Obtain the last insert rowid from the given SQLite database
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # connection and return it
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Args:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # con - The database connection
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Returns:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # the result of SELECT last_insert_rowid()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable last_insert_rowid_stmt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists last_insert_rowid_stmt]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set last_insert_rowid_stmt [$con prepare {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ SELECT last_insert_rowid()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set results [$last_insert_rowid_stmt execute]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $results nextlist row
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lassign $row rowid
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $results close
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return $rowid
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc import {contents opts} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Import the snapshot in JSON encoding given in contents into the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # database and return the imported snapshot object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Args:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # contents - The JSON encoded snapshot as a string
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # opts - Options dict
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Returns:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # The imported snapshot as a snapshot object
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set data [json::json2dict $contents]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set type [dict get $data metadata type]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } on error {eMessage} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ error "Invalid format: no metadata/type field"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch $type {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ "org.macports/snapshot/v1" {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # This is the only supported version, processing continues below
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ error "Invalid format: unsupported type $type, possibly generated by a newer version of MacPorts"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ global registry::tdbc_connection
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists tdbc_connection]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ registry::tdbc_connect
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable import_snapshot_stmt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable import_port_stmt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ variable import_file_stmt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists import_snapshot_stmt]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set import_snapshot_stmt [$tdbc_connection prepare {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ INSERT INTO snapshots (
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ created_at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , note
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ) VALUES (
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ :created_at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :note
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists import_port_stmt]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set import_port_stmt [$tdbc_connection prepare {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ INSERT INTO snapshot_ports (
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ snapshots_id
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , port_name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , requested
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , state
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , requested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ) VALUES (
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ :snapshot_id
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :port_name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :requested
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :state
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :requested_variants
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {![info exists import_file_stmt]} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set import_file_stmt [$tdbc_connection prepare {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ INSERT INTO snapshot_files (
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ id
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ) VALUES (
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ :port_id
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ , :path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set created_at [dict get $data metadata created_at]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set note [dict get $data metadata note]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set ports [dict get $data ports]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set counter 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set total [llength $ports]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set fancy_output [expr {![macports::ui_isset ports_debug] && [info exists macports::ui_options(progress_generic)]}]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if {$fancy_output} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set progress $macports::ui_options(progress_generic)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ proc noop {args} {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set progress noop
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $progress start
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $progress update $counter $total
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $tdbc_connection transaction {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $import_snapshot_stmt execute
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set snapshot_id [_last_insert_rowid $tdbc_connection]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach port $ports {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ incr counter
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ui_debug "Processing port $counter/$total: [dict get $port port_name]"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dict set port snapshot_id $snapshot_id
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $import_port_stmt execute $port
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set port_id [_last_insert_rowid $tdbc_connection]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ foreach path [dict get $port port_files] {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $import_file_stmt execute
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $progress update $counter $total
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ $progress finish
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return [registry::snapshot get_by_id $snapshot_id]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> proc create {opts} {
registry::write {
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/port/port.tcl b/src/port/port.tcl
</span><span style='display:block; white-space:pre;color:#808080;'>index 743ec7c56..bb70731dd 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/port/port.tcl
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/port/port.tcl
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -4237,7 +4237,7 @@ set cmd_opts_array [dict create {*}{
</span> reclaim {enable-reminders disable-reminders}
fetch {no-mirrors}
bump {patch}
<span style='display:block; white-space:pre;background:#ffe0e0;'>- snapshot {create list {diff 1} all {delete 1} help {note 1} {export 1} import}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ snapshot {create list {diff 1} all {delete 1} help {note 1} {export 1} {import 1}}
</span> restore {{snapshot-id 1} all last}
migrate {continue all}
}]
</pre><pre style='margin:0'>
</pre>