utmapp / UTM

Virtual machines for iOS and macOS
https://getutm.app
Apache License 2.0
26.91k stars 1.34k forks source link

JXA Examples? #6403

Open dronenb opened 5 months ago

dronenb commented 5 months ago

Hi all,

First off, thank you for all your work on UTM. It is a very useful application.

I was looking for some assistance with utilizing the AppleScript scripting interface for UTM from within JXA. From reading the UTM.sdef from the Script Editor in JavaScript language mode, I came up with the following working example that lists VM's and give output in JSON format to STDOUT:

#!/usr/bin/env osascript -l JavaScript

const app = Application('UTM');
let vms = app.virtualMachines().map((vm) => {
    return JSON.parse(Automation.getDisplayString(vm.properties()));
});

// Output last statement to stdout
JSON.stringify(vms);

I am interested in creating VM's as well, but have not had much luck. Here is what I have attemped thus far:

Attempt 1:

#!/usr/bin/env osascript -l JavaScript
const utm = Application("UTM");
let config = utm.QemuConfiguration(
    {
        "name":"test",
        "notes":"",
        "architecture":"aarch64",
        "memory":4096,
        "cpuCores":0,
        "hypervisor":true,
        "uefi":true,
        "directoryShareMode":"VirtFS",
        "drives":[],
        "networkInterfaces":[],
        "serialPorts":[],
        "machine":"virt"
    }
);

var vm = utm.VirtualMachine(
    {
        "backend":"qemu",
        "configuration": config
    }
);
utm.virtualMachines.push(vm);

Attempt 2:

#!/usr/bin/env osascript -l JavaScript
const utm = Application('UTM');
const config = utm.QemuConfiguration(
    {
        "name":"test",
        "notes":"",
        "architecture":"aarch64",
        "memory":4096,
        "cpuCores":0,
        "hypervisor":true,
        "uefi":true,
        "directoryShareMode":"VirtFS",
        "drives":[],
        "networkInterfaces":[],
        "serialPorts":[],
        "machine":"virt"
    }
);
const vm = utm.make(
    {
        "new": "virtualMachine",
        "withProperties":   {
            "backend"   :"qemu",
            "configuration" : config,
        }
    }
);

Attempt 3:

#!/usr/bin/env osascript -l JavaScript
const utm = Application('UTM');

const vm = utm.make(
    {
        "new": "virtualMachine",
        "withProperties":   {
            "backend"   :"qemu",
            "configuration" : {
                "name":"test",
                "notes":"",
                "architecture":"aarch64",
                "memory":4096,
                "cpuCores":0,
                "hypervisor":true,
                "uefi":true,
                "directoryShareMode":"VirtFS",
                "drives":[],
                "networkInterfaces":[],
                "serialPorts":[],
                "machine":"virt"
            }
        }
    }
);

Attempts 1 and 2 yield: execution error: Error: Error: A valid configuration must be specified. (-2700) Attempt 3 yields: execution error: Error: Error: Can't convert types. (-1700)

I think I am close here, but I could use some assistance. If we get something working, I would love to help get some JXA examples documented alongside the AppleScript examples in the scripting cheat sheet, as I imagine most people are more familiar with JavaScript than AppleScript.

JXA Resources

osy commented 2 months ago

I believe you can debug scripting errors by using the Console. For example, attempt 3 shows:

<NSAppleEventDescriptor: { 'usrf':[ 'utxt'("name"), 'utxt'("test"), 'utxt'("notes"), 'utxt'(""), 'utxt'("architecture"), 'utxt'("aarch64"), 'utxt'("memory"), 4096, 'utxt'("cpuCores"), 0, 'utxt'("hypervisor"), 'true'("true"), 'utxt'("uefi"), 'true'("true"), 'utxt'("directoryShareMode"), 'utxt'("VirtFS"), 'utxt'("drives"), [  ], 'utxt'("networkInterfaces"), [  ], 'utxt'("serialPorts"), [  ], 'utxt'("machine"), 'utxt'("virt") ] }>
2024-08-19 19:03:58.188081-0500 UTM[42269:535331]     Expected type descriptor: <NSAppleEventDescriptor: [ 'QeCf', 'ApCf' ]>

This is because backend expects an enum type. I don't know JXA so I'm not sure how to specify enums. Someone here seems to have a similar issue: https://forums.developer.apple.com/forums/thread/116397

Anyways, if someone wants to contribute JXA versions of the cheatsheet, it would be great and would help me as well.

naveenrajm7 commented 2 months ago

Hello,

I have written two plugins for UTM which use Apple Scripting bridge extensively. My first choice was to write JXA scripts since I am familiar with JS. However, I found that even a simple call like update configuration which works in apple script will not work in JXA. So I had to abandon JXA and use AppleScript, I still use JXA when I need programmatic data sharing through JSON but for everything else I use apple script. I have documented my UTM API decisions here https://naveenrajm7.github.io/vagrant_utm/internals/utm_api.html

Side note about passing enums, while using Apple Script I use the enum strings directly ( Eg: "TcPp" for TCP protocol ) See all the scripts I have https://github.com/naveenrajm7/vagrant_utm/tree/main/lib/vagrant_utm/scripts

Takeaway, It's really tricky to get JXA working.

dronenb commented 2 months ago

@naveenrajm7 seema like you arrived at the same conclusion that I had - JXA is great for data interchange since it can output JSON, but for whatever reason it seems like modifying any UTM objects through JXA is not possible for whatever reason, or at least I have not been able to make it work...

osy commented 2 months ago

I think the main issue is the use of enums. Wonder how other JXA apps handle it