diff --git a/Documentation/Installation.md b/Documentation/Installation.md new file mode 100644 index 0000000..0c3eeb8 --- /dev/null +++ b/Documentation/Installation.md @@ -0,0 +1,23 @@ +# Installation + +## Installing on Windows® and Linux +The easiest way to install this package and required dependencies for Google Cloud Product Interfaces is to clone the top-level repository using: + +```bash +git clone --recursive https://github.com/mathworks-ref-arch/matlab-gcp-common.git +``` + +### Build the google-cloud SDK for Java components +The MATLAB code uses the Google Cloud client library for Java and can be built using: +```bash +cd matlab-gcp-common/Software/Java +mvn clean package +``` + +Once built, change directory to the ```Software/MATLAB``` folder and use the ```startup.m``` function to initialize the interface for all other Google cloud interfaces. +```bash +cd matlab-gcp-common/Software/MATLAB +startup +``` + +[//]: # (Copyright 2020 The MathWorks, Inc.) diff --git a/Documentation/README.md b/Documentation/README.md new file mode 100644 index 0000000..2fd8738 --- /dev/null +++ b/Documentation/README.md @@ -0,0 +1,7 @@ +# MATLAB Interface *for Google Cloud Platform* Common Package +The code in this repository serves as common utility for building a Java SDK essential for other Google Cloud Product interfaces to function. + +## Contents +1. [Building GCP SDK](Installation.md) + +[//]: # (Copyright 2020 The MathWorks, Inc.) diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..f107cc2 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,17 @@ +MATHWORKS CLOUD REFERENCE ARCHITECTURE LICENSE + +The files in this GitHub repository refer to commercial software products and services, virtual machine images, and related materials of The MathWorks, Inc. (“MathWorks Programs”). MathWorks Programs are separately licensed under the MathWorks Software License Agreement, available in the desktop installation of the MathWorks Programs or in the virtual machine image. The files in this GitHub repository may also refer to third-party software licensed under separate terms provided by such third parties. + +The following license terms apply only to the files in this GitHub repository, including files in this folder and its subfolders, and do not apply to MathWorks Programs. References to “software” and “code” in the following license terms refer to the files in this GitHub repository. + +Copyright (c) 2020, The MathWorks, Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +3. In all cases, the software is, and all modifications and derivatives of the software shall be, licensed to you solely for use in conjunction with MathWorks products and service offerings. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..74cb407 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# MATLAB® Interface *for Google Cloud Platform* Common Package + +Common components used across MATLAB® interfaces for Google Cloud Platform™ services, for example Google Cloud Storage™. +Please refer to the [parent project](https://github.com/mathworks-ref-arch/mathworks-gcp-support) for usage instructions. + +## Requirements +### MathWorks products +* Requires MATLAB release R2017b or later + +### 3rd party products +* Google Cloud access +* Google Cloud Project service account + +To build a required JAR file: +* [Maven](https://maven.apache.org/) +* JDK 8+ + +## Getting Started +Please refer to the documents in the [Documentation](Documentation/README.md) folder to get started, however in general the documentation that ships with each of the service interfaces will be of most relevance and the best place to start. + +## License +Please see the [LICENSE.md](LICENSE.md) file in this GitHub repository. + +## Enhancement Request +Provide suggestions for additional features or capabilities using the following link: +https://www.mathworks.com/products/reference-architectures/request-new-reference-architectures.html + +## Support +Email: `mwlab@mathworks.com` or please log an issue. + + +[//]: # (Copyright 2020 The MathWorks, Inc.) diff --git a/RELEASENOTES.md b/RELEASENOTES.md new file mode 100644 index 0000000..b50849e --- /dev/null +++ b/RELEASENOTES.md @@ -0,0 +1,8 @@ +# MATLAB Interface *for Google Cloud Platform* Common Package +# Release Notes + +## Release 0.1.0 (Jun 2020) +* Initial release as a standalone matlab-gcp-common package + + +[//]: # (Copyright 2020 The MathWorks, Inc.) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..e866234 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,6 @@ +# Reporting Security Vulnerabilities + +If you believe you have discovered a security vulnerability, please report it to +[security@mathworks.com](mailto:security@mathworks.com). Please see +[MathWorks Vulnerability Disclosure Policy for Security Researchers](https://www.mathworks.com/company/aboutus/policies_statements/vulnerability-disclosure-policy.html) +for additional information. \ No newline at end of file diff --git a/Software/Java/pom.xml b/Software/Java/pom.xml new file mode 100644 index 0000000..acea2bf --- /dev/null +++ b/Software/Java/pom.xml @@ -0,0 +1,124 @@ + + 4.0.0 + com.mathworks.sdk + google-gcp-common-sdk + jar + 0.1.0 + google-gcp-common-sdk + http://www.mathworks.com + + + + + junit + junit + 3.8.1 + test + + + + + com.google.cloud + google-cloud-storage + 1.99.0 + + + + + + + MathWorks + http://www.mathworks.com + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.7 + 1.7 + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.0 + + + + com.mathworks.sdk.gcp.Version + + + ../MATLAB/lib/jar + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.0 + + + package + + shade + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + org.apache.http + shaded.org.apache.http + + + com.google.cloud.http.HttpTransportOption + shaded.com.google.http.HttpTransportOption + + + + com.google.common + shaded.com.google.common + + + com.google.protobuf + shaded.com.google.protobuf + + + com.google.api-client + shaded.com.google.api-client + + + com.google.http-client + shaded.com.google.http-client + + + com.google.guava + shaded.com.google.guava + + + com.google.oauth-client + shaded.com.google.oauth-client + + + + + + + + + + \ No newline at end of file diff --git a/Software/MATLAB/app/functions/Logger.m b/Software/MATLAB/app/functions/Logger.m new file mode 100644 index 0000000..df57b52 --- /dev/null +++ b/Software/MATLAB/app/functions/Logger.m @@ -0,0 +1,470 @@ +classdef Logger < handle + % Logger - Object definition for Logger + % --------------------------------------------------------------------- + % Abstract: A logger object to encapsulate logging and debugging + % messages for a MATLAB application. + % + % Syntax: + % logObj = Logger.getLogger(); + % + % Logger Properties: + % + % LogFileLevel - The level of log messages that will be saved to the + % log file + % + % DisplayLevel - The level of log messages that will be displayed + % in the command window + % + % LogFile - The file name or path to the log file. If empty, + % nothing will be logged to file. + % + % Messages - Structure array containing log messages + % + % Logger Methods: + % + % clearMessages(obj) - Clears the log messages currently stored in + % the Logger object + % + % clearLogFile(obj) - Clears the log messages currently stored in + % the log file + % + % write(obj,Level,MessageText) - Writes a message to the log + % + % Examples: + % logObj = Logger.getLogger(); + % write(logObj,'warning','My warning message') + % + + % Copyright 2020 The MathWorks, Inc. + % + % --------------------------------------------------------------------- + + %% Public properties + % These properties can be read or written to from outside the methods + % of this object. + properties + LogFileLevel = 'warning' %Log message level for messages to be saved + DisplayLevel = 'debug' %Log message level for messages to be displayed in the command window + LogFile = '' %Name or path to the log file + MsgPrefix = 'LOGGER:prefix' %prefix used for warning and error messages + end + + %% Read-only properties + % These properties are read-only, meaning they may be set only within + % methods of this object. + properties (SetAccess=protected, GetAccess=public) + Messages = struct('Timestamp',{},'LevelIndex',{},'LevelName',{},'Message',{},'ErrorDetails',{}) + end + + %% Hidden properties + % These properties are hidden values that may be needed by the class + % methods, but do not need to be exposed as gettable or settable + % properties. + properties (SetAccess=protected, GetAccess=protected) + FileId + end + + %% Constants + % These properties are constant values for this object. The value can + % not be changed. + properties (Constant=true) + % These are the different debugging levels, sorted from lowest to + % highest severity + ValidLevels = { + 'verbose' + 'debug' + 'warning' + 'error' + } + end + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Constructor + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % A constructor method is a special function that creates an instance + % of the class. Typically, constructor methods accept input arguments + % to assign the data stored in properties and always return an + % initialized object. + % + % This constructor is set to private to create a singleton class. This + % is to allow only one instance of the Logger, which + % can be retrieved from anywhere in the MATLAB session. + methods (Access = private) + function obj = Logger() + end + end %methods + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Destructor + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods + function delete(obj) + % If a log file was open, close it + if ~isempty(obj.FileId) + Status = fclose(obj.FileId); + % Warn if the file could not be closed + if Status~=0 + warning('Logger:CloseFile',... + 'Unable to close log file ''%s''.\n',... + obj.LogFile); + end + end + end + end %methods + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Static Methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Static methods are associated with a class, but not with specific + % instances of that class. These methods do not perform operations on + % individual objects of a class and, therefore, do not require an + % instance of the class as an input argument, like ordinary methods. + methods (Static = true) + function obj = getLogger() + % This method returns the singleton logger object. Only one + % logger is allowed in a MATLAB session, and this method will + % retrieve it. + + persistent SingletonLogger + + % Does the Logger need to be instantiated? + if isempty(SingletonLogger) || ~isvalid(SingletonLogger) + SingletonLogger = Logger; + end + + % Output the logger + obj = SingletonLogger; + + end + + function log(varargin) + logObj = Logger.getLogger(); + write(logObj, varargin{:}); + end + + function warning(varargin) + Logger.log('warning', varargin{:}); + end + + function debug(varargin) + Logger.log('debug', varargin{:}); + end + + function verbose(varargin) + Logger.log('verbose', varargin{:}); + end + + function error(varargin) + % Expect an MException to be returned if so catch it and throw as the + % caller to keep logger entries out of the console output + try + Logger.log('error', varargin{:}); + catch ME + throwAsCaller(ME); + end + end + + end %static methods + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Public Methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Methods are functions that implement the operations performed on + % objects of a class. They may be stored within the classdef file or as + % separate files in a @classname folder. + methods + + function clearMessages(obj) + % clearMessages - Method to clear messages in the Logger + % ------------------------------------------------------------------------- + % Abstract: Clears the log messages currently stored in the + % Logger object + % + % Syntax: + % logObj.clearMessages(Level) + % clearMessages(logObj) + % + % Inputs: + % logObj - Logger object + % + % Outputs: + % none + % + + obj.Messages(:) = []; + + end + + function clearLogFile(obj) + % clearLogFile - Method to clear messages in the log file + % ------------------------------------------------------------------------- + % Abstract: Clears the log messages currently stored in the log + % file + % + % Syntax: + % logObj.clearLogFile(Level) + % clearLogFile(logObj) + % + % Inputs: + % logObj - Logger object + % + % Outputs: + % none + % + + % Close the log file + obj.closeLogFile(); + + % Open the log file again and overwrite + openLogFile(obj,obj.LogFile,'w'); + + end + + + function write(obj,Level,MessageText,varargin) + % write - Method to write messages to the Logger + % ------------------------------------------------------------------------- + % Abstract: Adds a new message to the Logger, with the + % specified message level and text + % + % Syntax: + % logObj.write(Level,MessageText) + % write(logObj,Level,MessageText) + % write(logObj,Level,MessageText,myException) + % + % Inputs: + % logObj - Logger object + % Level - Message level string ('debug','warning',etc) + % MessageText - Message text string + % myException - A previously caught or created exception + % + % Outputs: + % none + % + % Examples: + % logObj = Logger.getLogger; + % write(logObj,'warning','My warning message') + % + + % Validate the level is one of the valid levels + Level = validatestring(Level,obj.ValidLevels); + + % Get the level of this message + idxLevel = find(strcmp(Level,obj.ValidLevels),1); + + if length(varargin) == 1 + if isa(varargin{1}, 'MException') + loggedException = varargin{1}; + else + error('Invalid argument: Expected an MException'); + end + else + % if an MException is not passed set it to empty + loggedException = []; + end + + % Save the message to the log + NewMessage = struct(... + 'Timestamp',now,... + 'LevelIndex',idxLevel,... + 'LevelName',Level,... + 'Message',MessageText,... + 'ErrorDetails',loggedException); + obj.Messages(end+1) = NewMessage; + + % Process the messages if the message is an error then an exception + % will be thrown which will be thrown as caller from this method + % of the Logger method to avoid entries from the Logger itself + try + obj.processMessage(NewMessage); + catch ME + throwAsCaller(ME); + end + end + + end %public methods + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Protected Methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Protected methods operate on the data in the object, but they can + % only be called from other methods of the class or subclass. + methods (Access = protected) + + function processMessage(obj,NewMessage) + % Called from write() + % Handle the file logging first as if an error throwing the error + % will halt execution and the file logging (if enabled) will not + % happen + % Should the message be written to the log file? + FileLevelIdx = find(strcmp(obj.LogFileLevel,obj.ValidLevels),1); + if NewMessage.LevelIndex>=FileLevelIdx && ~isempty(obj.FileId) + % Create a comma delimited message, followed by a + % line terminator + fprintf(obj.FileId,'%s, %s, "%s"\r\n',... + datestr(NewMessage.Timestamp),... %current date & time + upper(NewMessage.LevelName),... %uppercase level string + NewMessage.Message); %message as quoted string + if strcmpi(NewMessage.LevelName,'error') + if ~isempty(NewMessage.ErrorDetails) + % If there an exception has been passed in log its message + % and stack trace + fprintf(obj.FileId,'ID: %s, message: "%s"\r\n',... + NewMessage.ErrorDetails.identifier,... + NewMessage.ErrorDetails.message); + for n = 1:numel(NewMessage.ErrorDetails.stack) + fprintf(obj.FileId,'ID: %s, file: %s, name: %s, line: %d\r\n',... + NewMessage.ErrorDetails.identifier,... + NewMessage.ErrorDetails.stack(n).file,... + NewMessage.ErrorDetails.stack(n).name,... + NewMessage.ErrorDetails.stack(n).line); + end + end + end + end + + % Should the message be displayed in the command window? + DispLevelIdx = find(strcmp(obj.DisplayLevel,obj.ValidLevels),1); + if NewMessage.LevelIndex>=DispLevelIdx + % If the level is 'warning' display it as a warning i.e. in red text + if strcmpi(NewMessage.LevelName, 'warning') + % Temporarily save the warning state, disable backtraces to remove references + % to the logger from output, issue the warning and restore the warning state + tmpWarningStruct = warning; + warning('off', 'backtrace'); + warning([obj.MsgPrefix, ' ', NewMessage.Message]); + warning(tmpWarningStruct); + elseif strcmpi(NewMessage.LevelName, 'error') + % If error level build and exception, make any existing + % exception a Cause and throw the exception + errException = MException(obj.MsgPrefix, NewMessage.Message); + if ~isempty(NewMessage.ErrorDetails) + errException = addCause(errException, NewMessage.ErrorDetails); + end + % Return errException to the top level of the Logger so it can be + % thrown as caller again thus avoiding spurious entries from the + % logger itself + throwAsCaller(errException); + else + % not a warning or an error so just display the message + disp(NewMessage.Message); + end + end + + + end %function processMessage + + + function StatusOk = openLogFile(obj,FileName,OpenType) + + % Was a file name passed in? + if nargin<2 + FileName = obj.FileName; + end + if nargin<3 + OpenType = 'a'; + end + + % Try to open the new log file + try + [fid, Message] = fopen(FileName,OpenType); + + % If it failed to open, display a message + if fid == -1 + Message = sprintf('Unable to open log file ''%s'' for writing: %s\n',... + FileName, Message); + fid = []; + end + + catch err + % If another error occurred, display a message + Message = sprintf('Unable to set log file ''%s'':\n %s\n',... + Value,err.Message); + fid = []; + end + + % Were there any errors? + StatusOk = isempty(Message); + if StatusOk + % Set the new file ID + obj.FileId = fid; + else + warning('Logger:OpenLogFile',... + 'Unable to open log file ''%s''.\n',... + FileName); + end + + end %function [fid, Message] = openFile(FileName) + + + function closeLogFile(obj) + + % If a log file was open, close it + if ~isempty(obj.FileId) + Status = fclose(obj.FileId); + % Warn if the file could not be closed + if Status~=0 + warning('Logger:CloseLogFile',... + 'Unable to close log file ''%s''.\n',... + obj.LogFile); + else + obj.FileId = []; + end + end + + end %function closeFile() + + end %protected methods + + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %% Set Methods + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + methods + % Set methods customize the behavior that occurs when a property value + % is set. + + function set.LogFileLevel(obj,Value) + + % Validate the setting is one of the valid levels + Value = validatestring(Value,obj.ValidLevels); + obj.LogFileLevel = Value; + + end %function set.LogFileLevel + + + function set.DisplayLevel(obj,Value) + % Validate the setting is one of the valid levels + Value = validatestring(Value,obj.ValidLevels); + obj.DisplayLevel = Value; + + end %function set.DisplayLevel + + + function set.LogFile(obj,Value) + + % Close the old log file + closeLogFile(obj) + + % Open the new log file + StatusOk = openLogFile(obj,Value); + + % Did it open the file successfully? + if StatusOk + % Keep the new log file name + obj.LogFile = Value; + else + % If it failed to open, revert and don't change the file name + openLogFile(obj); + end + + end %function set.LogFile + + end %set methods + +end %classdef diff --git a/Software/MATLAB/app/functions/gcproot.m b/Software/MATLAB/app/functions/gcproot.m new file mode 100644 index 0000000..c8ff98e --- /dev/null +++ b/Software/MATLAB/app/functions/gcproot.m @@ -0,0 +1,9 @@ +function [out] = gcproot(varargin) +% GCPROOT returns location of tooling + +% Copyright 2020 The MathWorks, Inc. +% + +out = fileparts(fileparts(fileparts(mfilename('fullpath')))); + +end %function diff --git a/Software/MATLAB/lib/jar/.gitkeep b/Software/MATLAB/lib/jar/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Software/MATLAB/startup.m b/Software/MATLAB/startup.m new file mode 100644 index 0000000..68affbb --- /dev/null +++ b/Software/MATLAB/startup.m @@ -0,0 +1,137 @@ +function startup(varargin) +%% STARTUP - Script to add my paths to MATLAB path +% This script will add the paths below the root directory into the MATLAB +% path. + +% Copyright 2020 The MathWorks, Inc. + +appStr = 'Adding MATLAB-GCP-COMMON SDK Paths'; +disp(appStr); +disp(repmat('-',1,numel(appStr))); + +%% Set up the paths to add to the MATLAB path +% This should be the only section of the code that you need to modify +% The second argument specifies whether the given directory should be +% scanned recursively +here = fileparts(mfilename('fullpath')); + +rootDirs={fullfile(here,'app'),true;... + fullfile(here,'lib'),false;... + fullfile(here,'config'),false;... + fullfile(here,'script'),false;... + fullfile(here,'sys','modules'),true;... + fullfile(here,'public'),true;... + }; + +%% Add the framework to the path +iAddFilteredFolders(rootDirs); + +%% Handle the modules for the project. +disp('Initializing all modules'); +modRoot = fullfile(here,'sys','modules'); + +% Get a list of all modules +mList = dir(fullfile(modRoot,'*.')); +for mCount = 1:numel(mList) + % Only add proper folders + dName = mList(mCount).name; + if ~strcmpi(dName(1),'.') + % Valid Module name + candidateStartup = fullfile(modRoot,dName,'startup.m'); + if exist(candidateStartup,'file') + % We have a module with a startup + run(candidateStartup); + else + % Create a cell and add it recursively to the path + iAddFilteredFolders({fullfile(modRoot,dName), true}); + end + end + +end + +%% Post path-setup operations +% Add your post-setup operations here. +disp('Running post setup operations'); + +iSafeAddToJavaPath(fullfile(gcproot,'lib','jar','google-gcp-common-sdk-0.1.0.jar')); + + +end + +%% iAddFilteredFolders Helper function to add all folders to the path +function iAddFilteredFolders(rootDirs) +% Loop through the paths and add the necessary subfolders to the MATLAB path +for pCount = 1:size(rootDirs,1) + + rootDir=rootDirs{pCount,1}; + if rootDirs{pCount,2} + % recursively add all paths + rawPath=genpath(rootDir); + + if ~isempty(rawPath) + rawPathCell=textscan(rawPath,'%s','delimiter',pathsep); + rawPathCell=rawPathCell{1}; + else + rawPathCell = {rootDir}; + end + + else + % Add only that particular directory + rawPath = rootDir; + rawPathCell = {rawPath}; + end + + % remove undesired paths + svnFilteredPath=strfind(rawPathCell,'.svn'); + gitFilteredPath=strfind(rawPathCell,'.git'); + slprjFilteredPath=strfind(rawPathCell,'slprj'); + sfprjFilteredPath=strfind(rawPathCell,'sfprj'); + rtwFilteredPath=strfind(rawPathCell,'_ert_rtw'); + + % loop through path and remove all the .svn entries + if ~isempty(svnFilteredPath) + for pCount=1:length(svnFilteredPath) %#ok + filterCheck=[svnFilteredPath{pCount},... + gitFilteredPath{pCount},... + slprjFilteredPath{pCount},... + sfprjFilteredPath{pCount},... + rtwFilteredPath{pCount}]; + if isempty(filterCheck) + iSafeAddToPath(rawPathCell{pCount}); + else + % ignore + end + end + else + iSafeAddToPath(rawPathCell{pCount}); + end + +end + +end + +%% Helper function to add to MATLAB path. +function iSafeAddToPath(pathStr) + +% Add to path if the file exists +if exist(pathStr,'dir') + disp(['Adding ',pathStr]); + addpath(pathStr); +else + disp(['Skipping ',pathStr]); +end + +end + +%% Helper function to add to the Dynamic Java classpath +function iSafeAddToJavaPath(pathStr) + +% Add to path if the file exists +if exist(pathStr,'file') + disp(['Adding ',pathStr]); + javaaddpath(pathStr); +else + disp(strcat("Java library ",pathStr," missing.","Follow instructions in Installation.md to build the jar")); +end + +end