-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path__init__.py
More file actions
184 lines (151 loc) · 6.7 KB
/
Copy path__init__.py
File metadata and controls
184 lines (151 loc) · 6.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# -*- coding: utf-8 -*-
# Copyright (c) 2024 Manuel Schneider
from albert import *
from sys import platform
from contextlib import contextmanager
md_iid = "5.0"
md_version = "2.2.1"
md_name = "VirtualBox"
md_description = "Manage your VirtualBox machines"
md_license = "MIT"
md_url = "https://github.com/albertlauncher/albert-plugin-python-virtualbox"
md_readme_url = "https://github.com/albertlauncher/albert-plugin-python-virtualbox/blob/main/README.md"
md_authors = ["@ManuelSchneid3r"]
class Plugin(PluginInstance, GlobalQueryHandler):
def __init__(self):
PluginInstance.__init__(self)
GlobalQueryHandler.__init__(self)
if platform == "darwin":
self.icon_factory = lambda: Icon.fileType("/Applications/VirtualBox.app")
elif platform == "linux":
self.icon_factory = lambda: Icon.theme("virtualbox")
else:
raise NotImplementedError("Unhandled platform. Port me!")
try:
import vboxapi
except ImportError:
self.installSDK()
try:
import vboxapi
except ImportError:
raise ImportError(f"Failed to import vboxapi despite successful SDK installation.")
self.vbox_manager = vboxapi.VirtualBoxManager(None, None)
self.vbox_constants = self.vbox_manager.constants
self.vbox = self.vbox_manager.getVirtualBox()
def installSDK(self):
import hashlib
import os
import shutil
import zipfile
import urllib.request
import subprocess
cache_location = self.cacheLocation()
cache_location.mkdir(parents=True)
try:
url = "https://download.virtualbox.org/virtualbox/7.0.26/VirtualBoxSDK-7.0.26-168464.zip"
sha_expected = "504a5a7ea468ad1d19041379c8204287c73eb18926b51d51f269269dbcde9b96"
filename = cache_location / os.path.basename(url)
info(f"Downloading SDK ...")
urllib.request.urlretrieve(url, filename)
sha256 = hashlib.sha256()
with open(filename, "rb") as f:
for block in iter(lambda: f.read(8192), b""):
sha256.update(block)
sha_actual = sha256.hexdigest()
if sha_actual.lower() != sha_expected.lower():
raise ValueError("Downloaded file failed integrity check.")
info(f"Extracting SDK ...")
with zipfile.ZipFile(filename, 'r') as zip_ref:
zip_ref.extractall(cache_location)
info(f"Installing SDK ...")
if platform == "darwin":
VBOX_INSTALL_PATH = "/Applications/VirtualBox.app/Contents/MacOS/"
elif platform == "linux":
VBOX_INSTALL_PATH = "/usr/lib/virtualbox"
else:
raise NotImplementedError("Unhandled platform. See README.")
# 7.2 has pyproject toml echo 'VBOX_INSTALL_PATH="{VBOX_INSTALL_PATH}" pip install "{cache_location / "sdk/installer/vboxapi"}"';
# Okt 25 TODO
script = f"""
source "{self.dataLocation().parent}/python/venv/bin/activate"
pip install setuptools
cd "{cache_location / "sdk/installer"}"
VBOX_INSTALL_PATH="{VBOX_INSTALL_PATH}" python vboxapisetup.py install
"""
subprocess.run(["sh", "-c", script], check=True)
finally:
shutil.rmtree(cache_location)
def defaultTrigger(self):
return 'vbox '
def configWidget(self):
return [{
'type': 'label',
'text': f"Please read the [README.md]({md_readme_url}) for details.",
'widget_properties': { 'textFormat': 'Qt::MarkdownText' }
}]
def buildItem(self, vm):
actions = []
state = vm.state
if state in [self.vbox_constants.MachineState_PoweredOff, self.vbox_constants.MachineState_Aborted]:
actions.append(Action("startvm", "Start virtual machine", lambda m=vm: self.startVm(m)))
if state == self.vbox_constants.MachineState_Saved:
actions.append(Action("restorevm", "Start saved virtual machine", lambda m=vm: self.startVm(m)))
actions.append(Action("discardvm", "Discard saved state", lambda m=vm: self.discardSavedVm(m)))
if state == self.vbox_constants.MachineState_Running:
actions.extend([
Action("savevm", "Save virtual machine", lambda m=vm: self.saveVm(m)),
Action("poweroffvm", "Power off via ACPI", lambda m=vm: self.acpiPowerVm(m)),
Action("stopvm", "Turn off virtual machine", lambda m=vm: self.stopVm(m)),
Action("pausevm", "Pause virtual machine", lambda m=vm: self.pauseVm(m))
])
if state == self.vbox_constants.MachineState_Paused:
actions.append(Action("resumevm", "Resume virtual machine", lambda m=vm: self.resumeVm(m)))
return StandardItem(
id=vm.id,
text=vm.name,
subtext=self.vbox_manager.getEnumValueName("MachineState", vm.state),
input_action_text=vm.name,
icon_factory=self.icon_factory,
actions=actions
)
def handleGlobalQuery(self, query):
items = []
matcher = Matcher(query.string)
for vm in self.vbox_manager.getArray(self.vbox, "machines"):
if m := matcher.match(vm.name):
items.append(RankItem(self.buildItem(vm), m))
return items
def startVm(self, vm):
try:
info(f"Starting VM {vm.name} {type(vm)}...")
session = self.vbox_manager.getSessionObject(self.vbox)
progress = vm.launchVMProcess(session, 'gui', '')
progress.waitForCompletion(-1)
except Exception as e:
warning(str(e))
@contextmanager
def sharedLockedSession(self, vm):
session = self.vbox_manager.getSessionObject(self.vbox)
try:
vm.lockMachine(session, self.vbox_constants.LockType_Shared)
yield session
finally:
session.unlockMachine()
def acpiPowerVm(self, vm):
with self.sharedLockedSession(vm) as s:
s.console.powerButton()
def stopVm(self, vm):
with self.sharedLockedSession(vm) as s:
s.console.powerDown()
def saveVm(self, vm):
with self.sharedLockedSession(vm) as s:
s.console.saveState()
def discardSavedVm(self, vm):
with self.sharedLockedSession(vm) as s:
s.machine.discardSavedState()
def resumeVm(self, vm):
with self.sharedLockedSession(vm) as s:
s.console.resume()
def pauseVm(self, vm):
with self.sharedLockedSession(vm) as s:
s.console.pause()