<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>