full macOS support

All coins and features supported on Linux are now supported on macOS

Testing:

    $ test/test-release.sh -F
This commit is contained in:
The MMGen Project 2024-08-29 11:17:24 +00:00
commit bcff2e4fa3
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
12 changed files with 70 additions and 13 deletions

View file

@ -1 +1 @@
15.0.dev3
15.0.dev4

View file

@ -42,7 +42,7 @@ class File:
import stat
if stat.S_ISBLK(st.st_mode):
if sys.platform in ('win32', 'darwin'):
if sys.platform in ('win32',):
die(2, 'Access to raw block devices not supported on platform {sys.platform!r}')
mode = (os.O_RDONLY,os.O_RDWR)[bool(write)]
try:
@ -52,7 +52,11 @@ class File:
die(2,f'{fn!r}: permission denied')
# if e.errno != 17: raise
else:
self.size = os.lseek(fd, 0, os.SEEK_END)
if sys.platform == 'linux':
self.size = os.lseek(fd, 0, os.SEEK_END)
elif sys.platform == 'darwin':
from .platform.darwin.util import get_device_size
self.size = get_device_size(fn)
os.close(fd)
else:
self.size = st.st_size

View file

@ -86,7 +86,7 @@ def _check_file_type_and_access(fname,ftype,blkdev_ok=False):
(stat.S_ISLNK,'symbolic link')
]
if blkdev_ok:
if not sys.platform in ('win32', 'darwin'):
if not sys.platform in ('win32',):
ok_types.append((stat.S_ISBLK, 'block device'))
try:

View file

@ -18,6 +18,16 @@ from subprocess import run, PIPE, DEVNULL
from ...color import cyan
from ...obj import MMGenLabel
def get_device_size(fn):
import re
cp = run(['diskutil', 'info', fn], text=True, stdout=PIPE, check=True)
res = [e for e in cp.stdout.splitlines() if 'Disk Size' in e]
errmsg = '‘diskutil info’ output could not be parsed for device size'
assert len(res) == 1, f'{errmsg}:\n{cp.stdout}'
m = re.search(r'\((\d+) Bytes\)', res[0])
assert m, f'{errmsg}:\n{res[0]}'
return int(m[1])
class RamDiskLabel(MMGenLabel):
max_len = 24
desc = 'ramdisk label'

View file

@ -133,6 +133,7 @@ class bitcoin_cash_node_daemon(bitcoin_core_daemon):
nonstd_datadir = True
datadirs = {
'linux': [gc.home_dir,'.bitcoin-bchn'],
'darwin': [gc.home_dir, 'Library', 'Application Support', 'Bitcoin-Cash-Node'],
'win32': [os.getenv('APPDATA'),'Bitcoin-Cash-Node']
}
@ -162,5 +163,6 @@ class litecoin_core_daemon(bitcoin_core_daemon):
cfg_file_hdr = '# Litecoin Core config file\n'
datadirs = {
'linux': [gc.home_dir,'.litecoin'],
'darwin': [gc.home_dir, 'Library', 'Application Support', 'Litecoin'],
'win32': [os.getenv('APPDATA'),'Litecoin']
}

View file

@ -63,12 +63,14 @@ class openethereum_daemon(ethereum_daemon):
cfg_file = 'parity.conf'
datadirs = {
'linux': [gc.home_dir,'.local','share','io.parity.ethereum'],
'darwin': [gc.home_dir, 'Library', 'Application Support', 'io.parity.ethereum'],
'win32': [os.getenv('LOCALAPPDATA'),'Parity','Ethereum']
}
def init_subclass(self):
ld = self.platform == 'linux' and not self.opt.no_daemonize
self.use_pidfile = self.platform == 'linux' and not self.opt.no_daemonize
self.use_threads = self.platform in ('win32', 'darwin')
self.coind_args = list_gen(
['--no-ws'],
@ -81,8 +83,8 @@ class openethereum_daemon(ethereum_daemon):
['--config=dev', self.network=='regtest'], # no presets for mainnet or testnet
['--mode=offline', self.test_suite or self.network=='regtest'],
[f'--log-file={self.logfile}', self.non_dfl_datadir],
['daemon', ld],
[self.pidfile, ld],
['daemon', self.use_pidfile],
[self.pidfile, self.use_pidfile],
)
class parity_daemon(openethereum_daemon):
@ -104,6 +106,7 @@ class geth_daemon(ethereum_daemon):
version_info_arg = 'version'
datadirs = {
'linux': [gc.home_dir,'.ethereum','geth'],
'darwin': [gc.home_dir, 'Library', 'Ethereum', 'geth'],
'win32': [os.getenv('LOCALAPPDATA'),'Geth'] # FIXME
}

View file

@ -12,7 +12,7 @@
proto.xmr.daemon: Monero base protocol daemon classes
"""
import os
import sys, os
from ...cfg import gc
from ...util import list_gen,die,contains_any
@ -28,6 +28,7 @@ class monero_daemon(CoinDaemon):
cfg_file = 'bitmonero.conf'
datadirs = {
'linux': [gc.home_dir,'.bitmonero'],
'darwin': [gc.home_dir,'.bitmonero'],
'win32': ['/','c','ProgramData','bitmonero']
}
@ -53,6 +54,8 @@ class monero_daemon(CoinDaemon):
test_connection = False,
daemon = self )
self.use_pidfile = sys.platform == 'linux'
self.shared_args = list_gen(
['--no-zmq'],
[f'--p2p-bind-port={self.p2p_port}', self.p2p_port],
@ -64,7 +67,7 @@ class monero_daemon(CoinDaemon):
['--hide-my-port'],
['--no-igd'],
[f'--data-dir={self.datadir}', self.non_dfl_datadir],
[f'--pidfile={self.pidfile}', self.platform == 'linux'],
[f'--pidfile={self.pidfile}', self.use_pidfile],
['--detach', not (self.opt.no_daemonize or self.platform=='win32')],
['--offline', not self.opt.online],
)
@ -132,6 +135,8 @@ class MoneroWalletDaemon(RPCDaemon):
self.pidfile = os.path.join(self.datadir,id_str+'.pid')
self.logfile = os.path.join(self.datadir,id_str+'.log')
self.use_pidfile = sys.platform == 'linux'
self.proxy = proxy
self.monerod_addr = monerod_addr
self.monerod_port = (

View file

@ -91,7 +91,7 @@ class MoneroRPCClient(RPCClient):
),json_rpc=False)
async def do_stop_daemon(self,silent=False):
return self.call_raw('stop_daemon')
return self.call_raw('stop_daemon') # unreliable on macOS (daemon stops, but closes connection)
rpcmethods = ( 'get_info', )
rpcmethods_raw = ( 'get_height', 'send_raw_transaction', 'stop_daemon' )

View file

@ -172,7 +172,7 @@ class CmdTestWalletConv(CmdTestBase,CmdTestShared):
b = VirtBlockDevice(os.path.join(self.tmpdir, 'hincog_blkdev_img'), '1K')
b.create()
b.attach(dev_mode='0666')
b.attach(dev_mode='0666' if sys.platform == 'linux' else None)
self.ref_hincog_conv_out(ic_f=b.dev)
b.detach()

View file

@ -48,7 +48,7 @@ from .ct_base import CmdTestBase
# atexit functions:
def stop_daemons(self):
for v in self.users.values():
if '--restricted-rpc' in v.md.start_cmd:
if sys.platform == 'darwin' or '--restricted-rpc' in v.md.start_cmd:
v.md.stop()
else:
async_run(v.md_rpc.stop_daemon())

View file

@ -421,3 +421,33 @@ class VirtBlockDeviceLinux(VirtBlockDeviceBase):
def do_detach(self, dev, check=True):
do_run(['/sbin/losetup', '-d', dev], check=check)
class VirtBlockDeviceMacOS(VirtBlockDeviceBase):
def __init__(self, img_path, size):
self.img_path = Path(img_path + '.dmg').resolve()
self.size = size
def _get_associations(self):
cp = run(['hdiutil', 'info'], stdout=PIPE, stderr=PIPE, text=True, check=False)
if cp.returncode == 0:
lines = cp.stdout.splitlines()
out = [re.sub('.* ', '', s.strip()) for s in lines if re.match(r'image-path|/dev/', s)]
def gen_pairs():
for n in range(len(out) // 2):
yield(out[n*2], out[(n*2)+1])
return [dev for path, dev in gen_pairs() if path == str(self.img_path)]
else:
return []
def get_new_dev(self):
return None
def do_create(self, size, path):
do_run(['hdiutil', 'create', '-size', size, '-layout', 'NONE', str(path)])
def do_attach(self, path, dev=None):
do_run(['hdiutil', 'attach', '-mount', 'suppressed', str(path)])
def do_detach(self, dev, check=True):
do_run(['hdiutil', 'detach', dev], check=check)

View file

@ -240,7 +240,10 @@ class unit_tests:
await c.stop_daemon()
if not cfg.no_daemon_stop:
await md.rpc.stop_daemon()
if sys.platform == 'darwin':
md.stop()
else:
await md.rpc.stop_daemon()
gmsg('OK')