From 449a0f538c7421a9f75fd777ff565c5654e736ac Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 13 Nov 2025 10:11:25 +0100 Subject: [PATCH 1/7] Move fex dependencies to external folder in code directory --- code/+nansen/+config/+addons/@AddonManager/AddonManager.m | 3 +++ .../+nansen/+external/+fex/+datautil/merge_tables.m | 0 .../+nansen/+external/+fex/+sysutil/listPhysicalDrives.m | 0 .../+external/+fex/+sysutil/listPhysicalDrives_license.txt | 0 4 files changed, 3 insertions(+) rename code/{ => external/fileexchange}/+nansen/+external/+fex/+datautil/merge_tables.m (100%) rename code/{ => external/fileexchange}/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m (100%) rename code/{ => external/fileexchange}/+nansen/+external/+fex/+sysutil/listPhysicalDrives_license.txt (100%) diff --git a/code/+nansen/+config/+addons/@AddonManager/AddonManager.m b/code/+nansen/+config/+addons/@AddonManager/AddonManager.m index 84a3f258..c0179a3f 100644 --- a/code/+nansen/+config/+addons/@AddonManager/AddonManager.m +++ b/code/+nansen/+config/+addons/@AddonManager/AddonManager.m @@ -605,6 +605,9 @@ function checkIfAddonsAreOnPath() % Rename folder to remove main/master tag renamedDir = fullfile(rootDir, newName); + if isfolder(renamedDir) + rmdir(renamedDir, 's') + end movefile(newDir, renamedDir) folderPath = renamedDir; end diff --git a/code/+nansen/+external/+fex/+datautil/merge_tables.m b/code/external/fileexchange/+nansen/+external/+fex/+datautil/merge_tables.m similarity index 100% rename from code/+nansen/+external/+fex/+datautil/merge_tables.m rename to code/external/fileexchange/+nansen/+external/+fex/+datautil/merge_tables.m diff --git a/code/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m similarity index 100% rename from code/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m rename to code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m diff --git a/code/+nansen/+external/+fex/+sysutil/listPhysicalDrives_license.txt b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives_license.txt similarity index 100% rename from code/+nansen/+external/+fex/+sysutil/listPhysicalDrives_license.txt rename to code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives_license.txt From 28c785d92495ddb06c231fd7f4640c83ffe32217 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 13 Nov 2025 10:14:25 +0100 Subject: [PATCH 2/7] Rename listPhysicalDrives to listMountedDrives --- .../+dloc/@LocalRootPathManager/LocalRootPathManager.m | 4 ++-- .../+dataio/+dialog/editDataLocationRootDeviceName.m | 2 +- code/+nansen/+internal/+system/DiskConnectionMonitor.m | 2 +- .../{listPhysicalDrives.m => listMountedDrives.m} | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) rename code/external/fileexchange/+nansen/+external/+fex/+sysutil/{listPhysicalDrives.m => listMountedDrives.m} (97%) diff --git a/code/+nansen/+config/+dloc/@LocalRootPathManager/LocalRootPathManager.m b/code/+nansen/+config/+dloc/@LocalRootPathManager/LocalRootPathManager.m index 0121ccf9..d29b5588 100644 --- a/code/+nansen/+config/+dloc/@LocalRootPathManager/LocalRootPathManager.m +++ b/code/+nansen/+config/+dloc/@LocalRootPathManager/LocalRootPathManager.m @@ -164,7 +164,7 @@ function configureLocalRootPath(obj, localRootPath, originalRootPath) % name of the disk and the current letter assignment. if ispc - volumeInfo = nansen.external.fex.sysutil.listPhysicalDrives(); + volumeInfo = nansen.external.fex.sysutil.listMountedDrives(); for i = 1:numel(data) % Loop through DataLocations if ~isfield(data(i), 'RootPath') @@ -245,7 +245,7 @@ function updateVolumeInfo(obj, volumeInfo) % updateVolumeInfo(obj) updates volume info using system utilities. % updateVolumeInfo(obj, volumeInfo) uses the provided volume info. - import nansen.external.fex.sysutil.listPhysicalDrives + import nansen.external.fex.sysutil.listMountedDrives if nargin < 2 volumeInfo = listPhysicalDrives(); end diff --git a/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m b/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m index 4dad4563..067d388f 100644 --- a/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m +++ b/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m @@ -15,7 +15,7 @@ return end - volumeInfo = nansen.external.fex.sysutil.listPhysicalDrives(); + volumeInfo = nansen.external.fex.sysutil.listMountedDrives(); if ~isfield(dataLocationRootInfo, 'DiskType') [dataLocationRootInfo(:).DiskType] = deal('External'); diff --git a/code/+nansen/+internal/+system/DiskConnectionMonitor.m b/code/+nansen/+internal/+system/DiskConnectionMonitor.m index c6bca582..8f438539 100644 --- a/code/+nansen/+internal/+system/DiskConnectionMonitor.m +++ b/code/+nansen/+internal/+system/DiskConnectionMonitor.m @@ -106,7 +106,7 @@ function updateDiskList(obj, updatedVolumeList) function checkDiskPc(obj) %volumeList = system. - volumeInfoTable = nansen.external.fex.sysutil.listPhysicalDrives(); + volumeInfoTable = nansen.external.fex.sysutil.listMountedDrives(); % Convert string array to cell array of character vectors in % order to create struct array below diff --git a/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m similarity index 97% rename from code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m rename to code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m index a5fee343..bc7cf9a3 100755 --- a/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listPhysicalDrives.m +++ b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m @@ -1,8 +1,8 @@ -function infoTable = listPhysicalDrives() -%listPhysicalDrives List physical drives present on system +function infoTable = listMountedDrives() +%listMountedDrives List physical drives present on system % -% infoTable = system.listPhysicalDrives() returns a table which contains -% the following variables: +% infoTable = nansen.external.fex.sysutil.listMountedDrives() returns a table +% which contains the following variables: % % DeviceID : The device id (drive letter / disk number) % VolumeName : Name of drive / volume From 551a14090911dbd827dbd365fc284e5ad4b89f08 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 13 Nov 2025 10:16:12 +0100 Subject: [PATCH 3/7] Update listMountedDrives.m Added code for getting drive info on linux Removed wmic dependency --- .../+fex/+sysutil/listMountedDrives.m | 206 +++++++++++++----- 1 file changed, 146 insertions(+), 60 deletions(-) diff --git a/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m index bc7cf9a3..0055c508 100755 --- a/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m +++ b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m @@ -1,8 +1,8 @@ function infoTable = listMountedDrives() -%listMountedDrives List physical drives present on system +%listMountedDrives List mounted drives present on system % -% infoTable = nansen.external.fex.sysutil.listMountedDrives() returns a table -% which contains the following variables: +% infoTable = sysutil.drive.listMountedDrives() returns a table which contains +% the following variables: % % DeviceID : The device id (drive letter / disk number) % VolumeName : Name of drive / volume @@ -16,29 +16,31 @@ % PC : https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logicaldisk % Written by Eivind Hennestad | 2022-11-24 +% Updated by Claude Sonnet 4.5 | 2025-11-13 % Todo: -% [ ] Implement for linux systems % [ ] Add internal, external (how to get this on pc?) -% [ ] On mac, file system is not correct... -% [ ] On mac, don't show hidden partitions? -% [ ] On windows, is the serial number complete? -% [ ] On mac, add serial number +% [ ] On mac, file system is not correct... +% [ ] On mac, don't show hidden partitions? +% [ ] On mac, add serial number % [ ] On mac, parse result when using -plist instead? -% [ ] On windows, use 'where drivetype=3' i.e 'wmic logicaldisk where drivetype=3 get ...' +% [ ] On linux, add serial number (use lsblk -o +UUID or blkid) - if ismac + if ismac % Use diskutil [~, infoStr] = system('diskutil list physical'); infoTable = convertListToTableMac(infoStr); - elseif ispc - [~, infoStr] = system(['wmic logicaldisk get DeviceId, ', ... - 'VolumeName, VolumeSerialNumber, FileSystem, Size, ', ... - 'DriveType' ] ); + elseif ispc % Use PowerShell Get-Volume + [~, infoStr] = system(['powershell -Command "Get-Volume | ', ... + 'Where-Object {$_.DriveLetter} | ', ... + 'Select-Object DriveLetter, FileSystemLabel, FileSystem, ', ... + 'Size, DriveType | ', ... + 'ConvertTo-Csv -NoTypeInformation"']); infoTable = convertListToTablePc(infoStr); - elseif isunix - error('Not implemented for unix systems') + elseif isunix % Use lsblk + [~, infoStr] = system('lsblk -o NAME,LABEL,FSTYPE,SIZE,TYPE,MOUNTPOINT -P -b'); + infoTable = convertListToTableLinux(infoStr); end infoTable = postprocessTable(infoTable); @@ -59,7 +61,7 @@ infostrCell = splitStringIntoRows(infoStr); rowIdxRemove = strncmp(infostrCell, '/dev', 4); - + % Keep track of rows belonging to same drive / device deviceNumber = cumsum(rowIdxRemove); deviceHeaders = infostrCell(rowIdxRemove); @@ -94,7 +96,7 @@ expression = '\((.*)\)'; driveType = regexp(deviceHeaders, expression, 'tokens'); driveTypeColumnData = arrayfun(@(x) driveType{x}{1}{1}, deviceNumber, 'uni', 0); - + colIdx = size(C, 2) + 1; C(:, colIdx) = driveTypeColumnData; @@ -112,32 +114,50 @@ function infoTable = convertListToTablePc(infoStr) + % Parse CSV output from PowerShell Get-Volume infostrCell = splitStringIntoRows(infoStr); - % Detect indices where rows should be split - colStart = regexp(infostrCell{1}, '(?<=\ )\S{1}', 'start'); - colStart = [1, colStart]; + % Remove quotes and split by comma + C = cellfun(@(row) strsplit(strrep(row, '"', ''), ','), ... + infostrCell, 'UniformOutput', false); + C = vertcat(C{:}); - C = splitRowsIntoColumns(infostrCell, colStart); + % Rename columns to match expected format + C{1,1} = 'DeviceID'; + C{1,2} = 'VolumeName'; + C{1,3} = 'FileSystem'; + C{1,4} = 'Size'; + C{1,5} = 'DriveType'; - %C{1,6} = 'SerialNumber'; % Shorten name - C = strrep(C, 'VolumeSerialNumber', 'SerialNumber'); - infoTable = cell2table(C(2:end,:), 'VariableNames',C(1,:)); + % Add colon to drive letters + C(2:end, 1) = cellfun(@(x) [x, ':'], C(2:end, 1), 'UniformOutput', false); + + infoTable = cell2table(C(2:end,:), 'VariableNames', C(1,:)); % Compute size and add unit - infoTable.Size = str2double( infoTable.Size ); + infoTable.Size = str2double(infoTable.Size); power = floor(log10(infoTable.Size)/3)*3; infoTable.Size = infoTable.Size ./ 10.^(power); sizeUnit = categorical(power, [3, 6, 9, 12], {'kB', 'MB', 'GB', 'TB'}); infoTable = addvars(infoTable, sizeUnit, 'NewVariableNames', 'SizeUnit'); - + + % Add empty SerialNumber column (Get-Volume doesn't provide this easily) + serialNumber = repmat(missing, size(infoTable, 1), 1); + infoTable = addvars(infoTable, serialNumber, 'NewVariableNames', 'SerialNumber'); + + % Label drive types (handle empty values) + for i = 1:height(infoTable) + if isempty(infoTable.DriveType{i}) || strcmp(infoTable.DriveType{i}, '') + infoTable.DriveType{i} = '3'; % Default to Fixed for empty values + end + end infoTable.DriveType = labelDriveTypePC(infoTable.DriveType); end function infoStrCell = splitStringIntoRows(infoStr) - + % Split string into rows infoStrCell = textscan( infoStr, '%s', 'delimiter', '\n' ); infoStrCell = infoStrCell{1}; @@ -147,7 +167,7 @@ end function C = splitRowsIntoColumns(infostrCell, splitIdx) - + numRows = numel(infostrCell); numColumns = numel(splitIdx); @@ -165,23 +185,107 @@ colIdx = splitIdx(i) : splitIdx(i+1)-1; C(:, i) = cellfun(@(str) str(colIdx), infostrCell, 'uni', 0); end - + C = strtrim(C); % Remove trailing whitespace from all cells end function driveType = labelDriveTypePC(driveType) - - % 0 Unknown - % 1 No Root Directory - % 2 Removable Disk - % 3 Local Disk - % 4 Network Drive - % 5 Compact Disc - % 6 RAM Disk - - driveType = categorical(driveType, {'0','1','2','3','4','5','6'}, ... - {'Unknown', 'No Root Directory', 'Removable Disk', 'Local Disk', ... - 'Network Drive', 'Compact Disc', 'RAM Disk'}); + + % Map Get-Volume DriveType values to descriptive names + % Get-Volume returns: Unknown=0, Fixed=3, Removable=2, CD-ROM=5, Network=4 + + driveType = categorical(driveType, {'0','2','3','4','5'}, ... + {'Unknown', 'Removable', 'Fixed', 'Network', 'CD-ROM'}); +end + +function infoTable = convertListToTableLinux(infoStr) + + % Parse lsblk output (key="value" format) + infostrCell = splitStringIntoRows(infoStr); + + % Keep only mounted drives (has MOUNTPOINT) + mountedIdx = contains(infostrCell, 'MOUNTPOINT="/') | contains(infostrCell, 'MOUNTPOINT="/boot'); + infostrCell = infostrCell(mountedIdx); + + if isempty(infostrCell) + % Create empty table with correct structure + infoTable = cell2table(cell(0, 7), 'VariableNames', ... + {'DeviceID', 'VolumeName', 'SerialNumber', 'FileSystem', 'Size', 'SizeUnit', 'DriveType'}); + return; + end + + numRows = numel(infostrCell); + C = cell(numRows, 7); + + for i = 1:numRows + row = infostrCell{i}; + + % Extract key-value pairs + name = extractValue(row, 'NAME'); + label = extractValue(row, 'LABEL'); + fstype = extractValue(row, 'FSTYPE'); + sizeBytes = extractValue(row, 'SIZE'); + driveType = extractValue(row, 'TYPE'); + mountpoint = extractValue(row, 'MOUNTPOINT'); + + % DeviceID: /dev/name + C{i, 1} = ['/dev/', name]; + + % VolumeName: use label if available, otherwise mountpoint + if isempty(label) + C{i, 2} = mountpoint; + else + C{i, 2} = label; + end + + % SerialNumber: not easily available with lsblk + C{i, 3} = ''; + + % FileSystem + C{i, 4} = fstype; + + % Size (in bytes, will convert later) + C{i, 5} = sizeBytes; + + % SizeUnit (placeholder, will be computed) + C{i, 6} = 'B'; + + % DriveType + if strcmp(driveType, 'disk') + C{i, 7} = 'Fixed'; + elseif strcmp(driveType, 'part') + C{i, 7} = 'Partition'; + elseif strcmp(driveType, 'loop') + C{i, 7} = 'Loop'; + elseif strcmp(driveType, 'rom') + C{i, 7} = 'CD-ROM'; + else + C{i, 7} = driveType; + end + end + + infoTable = cell2table(C, 'VariableNames', ... + {'DeviceID', 'VolumeName', 'SerialNumber', 'FileSystem', 'Size', 'SizeUnit', 'DriveType'}); + + % Convert size to numeric and compute appropriate unit + infoTable.Size = str2double(infoTable.Size); + + power = floor(log10(infoTable.Size)/3)*3; + infoTable.Size = infoTable.Size ./ 10.^(power); + + sizeUnit = categorical(power, [3, 6, 9, 12], {'kB', 'MB', 'GB', 'TB'}); + infoTable.SizeUnit = sizeUnit; +end + +function value = extractValue(str, key) + % Extract value from KEY="VALUE" format + pattern = [key, '="([^"]*)"']; + tokens = regexp(str, pattern, 'tokens'); + if ~isempty(tokens) + value = tokens{1}{1}; + else + value = ''; + end end function infoTable = postprocessTable(infoTable) @@ -207,21 +311,3 @@ isEmptyCell = cellfun(@isempty, cellArray); cellArray( isEmptyCell ) = []; end - -% % % function filename = filewrite(filename, textString) -% % % -% % % if isempty(filename) -% % % filename = [tempname, '.txt']; -% % % end -% % % -% % % fid = fopen(filename, 'w'); -% % % fwrite(fid, textString); -% % % fclose(fid); -% % % end -% % % -% % % [~, infoStr] = system('diskutil list -plist physical'); -% % % -% % % filename = [tempname, '.xml']; -% % % filename = filewrite(filename, infoStr); -% % % -% % % convertedValue = readstruct(filename); From aa0e01e4ecf4497fca12a3924267f264d0573929 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 13 Nov 2025 10:23:38 +0100 Subject: [PATCH 4/7] Update DiskConnectionMonitor.m Added implementation for getting drives on Linux Added todo comments --- .../+internal/+system/DiskConnectionMonitor.m | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/code/+nansen/+internal/+system/DiskConnectionMonitor.m b/code/+nansen/+internal/+system/DiskConnectionMonitor.m index 8f438539..493254fa 100644 --- a/code/+nansen/+internal/+system/DiskConnectionMonitor.m +++ b/code/+nansen/+internal/+system/DiskConnectionMonitor.m @@ -1,5 +1,11 @@ classdef DiskConnectionMonitor < handle + % Todo + % - Streamline getting drive info from nansen.external.fex.sysutil.listMountedDrives + % - Create event data? + % - Add error handling + % - Use drive instead of disk in class/method/event names + properties (Dependent) TimerUpdateInterval end @@ -130,7 +136,14 @@ function checkDiskMac(obj) end function checkDiskUnix(obj) - error('Not implemented yet') + volumeInfoTable = nansen.external.fex.sysutil.listMountedDrives(); + + % Convert string array to cell array of character vectors in + % order to create struct array below + string2cellchar = @(strArray) arrayfun(@char, strArray, 'uni', false); %convertStringsToChars, cellstr + volumeList = struct('Name', string2cellchar(volumeInfoTable.VolumeName) ); + + obj.updateDiskList(volumeList) end end From 32bbca7fbd99aaab466ccf2553bbc7320d9d07d3 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 13 Nov 2025 10:28:16 +0100 Subject: [PATCH 5/7] Update editDataLocationRootDeviceName.m Removed error for linux --- .../+dialog/editDataLocationRootDeviceName.m | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m b/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m index 067d388f..b8d1fa7c 100644 --- a/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m +++ b/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m @@ -10,13 +10,18 @@ % [ ] Is it possible to indicate that the diskname is a dropdown? % [ ] Update dropdowns if drives are connected or disconnected - if isunix && ~ismac - errordlg('This feature is not implemented for linux/unix systems') - return + try + volumeInfo = nansen.external.fex.sysutil.listMountedDrives(); + catch MECause + + ME = MException('NANSEN:DataIO:FailedToListDrives', ... + ['Failed to list mounted drives using system command. ' ... + 'Please report if you see this error.']); + ME = ME.addCause(MECause); + errordlg('Failed to list mounted drives using system command. See MATLAB''s command window for details') + throw(ME) end - - volumeInfo = nansen.external.fex.sysutil.listMountedDrives(); - + if ~isfield(dataLocationRootInfo, 'DiskType') [dataLocationRootInfo(:).DiskType] = deal('External'); end From 46f1cbb5759cf0bc7aae2b0f17ba6ae83b454213 Mon Sep 17 00:00:00 2001 From: ehennestad Date: Thu, 13 Nov 2025 10:47:36 +0100 Subject: [PATCH 6/7] Improve error handling --- .../+dialog/editDataLocationRootDeviceName.m | 3 +- .../+internal/+system/DiskConnectionMonitor.m | 35 +++++++++++++--- .../+fex/+sysutil/listMountedDrives.m | 42 +++++++++++-------- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m b/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m index b8d1fa7c..16e58265 100644 --- a/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m +++ b/code/+nansen/+dataio/+dialog/editDataLocationRootDeviceName.m @@ -13,12 +13,11 @@ try volumeInfo = nansen.external.fex.sysutil.listMountedDrives(); catch MECause - ME = MException('NANSEN:DataIO:FailedToListDrives', ... ['Failed to list mounted drives using system command. ' ... 'Please report if you see this error.']); ME = ME.addCause(MECause); - errordlg('Failed to list mounted drives using system command. See MATLAB''s command window for details') + errordlg('Failed to list mounted drives using system command. See MATLAB''s command window for details.') throw(ME) end diff --git a/code/+nansen/+internal/+system/DiskConnectionMonitor.m b/code/+nansen/+internal/+system/DiskConnectionMonitor.m index 493254fa..84a4d4d6 100644 --- a/code/+nansen/+internal/+system/DiskConnectionMonitor.m +++ b/code/+nansen/+internal/+system/DiskConnectionMonitor.m @@ -3,7 +3,6 @@ % Todo % - Streamline getting drive info from nansen.external.fex.sysutil.listMountedDrives % - Create event data? - % - Add error handling % - Use drive instead of disk in class/method/event names properties (Dependent) @@ -28,11 +27,15 @@ methods function obj = DiskConnectionMonitor - if ismac || ispc - obj.initializeTimer() - else - % pass (not implemented for linux) + + if ispc || (isunix && ~ismac) + if ~obj.checkListDrivesWorks() + obj.displayListDrivesNotWorkingWarning() + return + end end + + obj.initializeTimer() end function delete(obj) @@ -145,6 +148,28 @@ function checkDiskUnix(obj) obj.updateDiskList(volumeList) end + + function tf = checkListDrivesWorks(~) + persistent listDrivesWorks + if isempty(listDrivesWorks) + try + nansen.external.fex.sysutil.listMountedDrives() + listDrivesWorks = true; + catch + listDrivesWorks = false; + end + end + tf = listDrivesWorks; + end + + function displayListDrivesNotWorkingWarning(~) + nansen.common.tracelesswarning(sprintf([... + 'Failed to list mounted drives using system command.\nIf you ', ... + 'want NANSEN to dynamically update when drives are ', ... + 'connected/disconnected, please run ', ... + '`nansen.external.fex.sysutil.listMountedDrives` and ', ... + 'report the error you are seeing.'])) + end end methods (Access = private) diff --git a/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m index 0055c508..610c9726 100755 --- a/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m +++ b/code/external/fileexchange/+nansen/+external/+fex/+sysutil/listMountedDrives.m @@ -26,24 +26,32 @@ % [ ] On mac, parse result when using -plist instead? % [ ] On linux, add serial number (use lsblk -o +UUID or blkid) - if ismac % Use diskutil - [~, infoStr] = system('diskutil list physical'); - infoTable = convertListToTableMac(infoStr); - - elseif ispc % Use PowerShell Get-Volume - [~, infoStr] = system(['powershell -Command "Get-Volume | ', ... - 'Where-Object {$_.DriveLetter} | ', ... - 'Select-Object DriveLetter, FileSystemLabel, FileSystem, ', ... - 'Size, DriveType | ', ... - 'ConvertTo-Csv -NoTypeInformation"']); - infoTable = convertListToTablePc(infoStr); - - elseif isunix % Use lsblk - [~, infoStr] = system('lsblk -o NAME,LABEL,FSTYPE,SIZE,TYPE,MOUNTPOINT -P -b'); - infoTable = convertListToTableLinux(infoStr); - end + try + if ismac % Use diskutil + [~, infoStr] = system('diskutil list physical'); + infoTable = convertListToTableMac(infoStr); + + elseif ispc % Use PowerShell Get-Volume + [~, infoStr] = system(['powershell -Command "Get-Volume | ', ... + 'Where-Object {$_.DriveLetter} | ', ... + 'Select-Object DriveLetter, FileSystemLabel, FileSystem, ', ... + 'Size, DriveType | ', ... + 'ConvertTo-Csv -NoTypeInformation"']); + infoTable = convertListToTablePc(infoStr); + + elseif isunix % Use lsblk + [~, infoStr] = system('lsblk -o NAME,LABEL,FSTYPE,SIZE,TYPE,MOUNTPOINT -P -b'); + infoTable = convertListToTableLinux(infoStr); + end - infoTable = postprocessTable(infoTable); + infoTable = postprocessTable(infoTable); + + catch MECause + ME = MException('SYSTEMUTIL:ListMountedDrives:FailedToListDrives', ... + 'Failed to list mounted drives using system command.'); + ME = ME.addCause(MECause); + throw(ME) + end end % % Local functions: From 5efa1ab9a502d99496af6b983bdc551db5864c1b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 13 Nov 2025 09:55:43 +0000 Subject: [PATCH 7/7] Update GitHub badges --- .github/badges/code_issues.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/badges/code_issues.svg b/.github/badges/code_issues.svg index 4387fdc0..8508a2c2 100644 --- a/.github/badges/code_issues.svg +++ b/.github/badges/code_issues.svg @@ -1 +1 @@ -code issuescode issues18151815 \ No newline at end of file +code issuescode issues18141814 \ No newline at end of file