Last active
March 8, 2020 03:17
-
-
Save TommasoBelluzzo/3e4100a92027d7b504171232fb1ac377 to your computer and use it in GitHub Desktop.
A script for detecting dependancies and minimum required version of other Matlab scripts.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% [INPUT] | |
% path = A string representing the path on which to perform the requirements check (optional, default=pwd). | |
% It can be either the path to a Matlab script or the path to a directory containing one or more Matlab scripts at any level of depth. | |
% type = A string representing the requirements check to perform (optional, default=ALL), its value can be one of the following: | |
% - ALL: dependancies and minimum version. | |
% - DEP: dependancies only. | |
% - VER: minimum version only. | |
% extv = A boolean indicating whether to return detailed information concerning the minimum version (optional, default=false). | |
% If false, the result is returned in the form of a string representing the minimum version. | |
% Otherwise, the result is returned in the form of a table listing all the called functions and their respective minimum version (if available). | |
% This parameter should be specified only when the minimum version check must be performed. | |
% | |
% [OUTPUT] | |
% out = The result of the requirements check, whose content depends upon "type" and "extv" input arguments: | |
% - ALL: a structure with two fields, "Deps" and "VerInfo", whose values are described below. | |
% - DEP: a cell array of strings that represent the name of the dependancies. | |
% - VER: if "extv" is false, a string representing the minimum version, otherwise an n-by-3 table listing all the called functions and their respective minimum version (if available). | |
function out = check_requirements(varargin) | |
persistent p; | |
if (isempty(p)) | |
p = inputParser(); | |
p.addOptional('path','',@(x)validateattributes(x,{'char','string'},{'scalartext','nonempty'})); | |
p.addOptional('type','ALL',@(x)any(validatestring(x,{'ALL','DEP','VER'}))); | |
p.addOptional('extv',false,@(x)validateattributes(x,{'logical'},{'scalar'})); | |
end | |
p.parse(varargin{:}); | |
res = p.Results; | |
path = strtrim(char(res.path)); | |
type = res.type; | |
extv = res.extv; | |
if ((nargin == 3) && strcmp(type,'DEP')) | |
error('The ''extv'' parameter should be specified only when the minimum version check must be performed.'); | |
end | |
if (isempty(path)) | |
path = pwd(); | |
end | |
search = exist(path); %#ok<EXIST> | |
files = []; | |
if (search == 2) | |
[~,~,ext] = fileparts(path); | |
if (strcmpi(ext,'.m')) | |
files = {path}; | |
end | |
elseif (search == 7) | |
files = find_scripts(path); | |
end | |
if (isempty(files)) | |
error('No scripts to analyse have been found.'); | |
end | |
out = check_requirements_internal(files,type,extv); | |
end | |
function out = check_requirements_internal(files,type,extv) | |
persistent dict; | |
if (isempty(dict)) | |
dict = containers.Map('KeyType','char','ValueType','any'); | |
end | |
files_len = numel(files); | |
if (any(strcmp(type,{'ALL' 'DEP'}))) | |
deps = cell(files_len,1); | |
for i = 1:files_len | |
[~,p] = matlab.codetools.requiredFilesAndProducts(files{i}); | |
deps{i} = {p.Name}; | |
end | |
deps = unique([deps{:}]); | |
end | |
if (any(strcmp(type,{'ALL' 'VER'}))) | |
funs = cell(files_len,1); | |
for i = 1:files_len | |
ci = getcallinfo(files{i},'flat'); | |
funs{i} = [ci.calls.atCalls.names ci.calls.dotCalls.names ci.calls.fcnCalls.names]; | |
end | |
funs = unique([funs{:}]).'; | |
funs_len = numel(funs); | |
vers = table(funs,NaN(funs_len,1),repmat({''},funs_len,1),'VariableNames',{'Function' 'Major' 'Minor'}); | |
funs = lower(funs); | |
for i = 1:funs_len | |
fun = funs{i}; | |
if (isKey(dict,fun)) | |
vers(i,[2 3]) = dict(fun); | |
continue; | |
end | |
html = download_page(['http://mathworks.com/help/matlab/ref/' fun '.html']); | |
if (isempty(html)) | |
html = download_page(['http://mathworks.com/help/simulink/slref/' fun '.html']); | |
end | |
if (isempty(html)) | |
continue; | |
end | |
tokens = regexp(html,'Introduced (?:before|in) R([0-9]+)(a|b)','tokens'); | |
if (numel(tokens) ~= 1) | |
continue; | |
end | |
tokens = [tokens{:}]; | |
values = {str2double(tokens{1}) tokens{2}}; | |
dict(fun) = values; | |
vers(i,[2 3]) = values; | |
end | |
vers_ko = isnan(vers.Major); | |
vers_clean = vers; | |
vers_clean(vers_ko,:) = []; | |
vers_clean = sortrows(vers_clean,[2 3],{'descend' 'descend'}); | |
if (isempty(vers_clean)) | |
if (extv) | |
ver_info = vers_clean; | |
else | |
ver_info = 'Unknown'; | |
end | |
else | |
if (extv) | |
ver_info = [vers_clean; vers(vers_ko,:)]; | |
else | |
ver_info = ['R' num2str(vers_clean{1,2}) char(vers_clean{1,3})]; | |
end | |
end | |
end | |
switch (type) | |
case 'DEP' | |
out = deps; | |
case 'VER' | |
out = ver_info; | |
otherwise | |
out = struct(); | |
out.Deps = deps; | |
out.VerInfo = ver_info; | |
end | |
end | |
function html = download_page(url) | |
if (verLessThan('Matlab','8.4')) | |
[html,status] = urlread(url); %#ok<URLRD> | |
if (status == 0) | |
html = ''; | |
end | |
else | |
try | |
html = webread(url); | |
catch | |
html = ''; | |
end | |
end | |
end | |
function files = find_scripts(folder) | |
pattern = [folder filesep() '*.m']; | |
f = ls(pattern); | |
if (isempty(f)) | |
files = {}; | |
else | |
files = strcat(folder,filesep(),cellstr(f)); | |
end | |
subfolders = cellstr(ls(folder)); | |
subfolders(1:2) = []; | |
subfolders(~cellfun(@isdir,strcat(folder,filesep(),subfolders))) = []; | |
subfolders_len = numel(subfolders); | |
subfiles = cell(subfolders_len,1); | |
for i = 1:subfolders_len | |
subfiles{i} = find_scripts([folder filesep() subfolders{i}]); | |
end | |
files = [files; vertcat(subfiles{:})]; | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment