www.gusucode.com > robotsimulink 工具箱 matlab源码程序 > robotsimulink/robotslros/+robotics/+codertarget/+internal/LinuxSystemInterface.m

    classdef LinuxSystemInterface < robotics.codertarget.internal.SystemInterface
    %This class is for internal use only. It may be removed in the future.
    
    %LinuxSystemInterface Define an interface for system operations supported on Linux hardware
    %
    %   LinuxSystemInterface is a abstract class which
    %   defines the interface methods for communicating with hardware running
    %   a Linux distribution.
    %
    %   The following methods are implemented by this class:
    %
    %   output = system(OBJ,COMMAND,SUDO) Called when a system command gets
    %   executed on the hardware. SUDO is an optional argument.
    %
    %   putFile(obj,localSrc,remoteDest) Copy localSrc on the host computer to
    %   remoteDest on the hardware.
    %
    %   getFile(obj,remoteSrc,localDest) Copy the remoteSrc on the hardware to
    %   to the localDest on the host computer.
    %
    %   a = dir(obj,fileSpec) Directory listing for fileSpec. The output a is a
    %   structure containing name, folder, isdir and bytes fields.
    
    %   Copyright 2015-2016 The MathWorks, Inc.
    
    properties (Abstract, Access = protected)
        Ssh
    end
    
    methods (Access = public)
        %% System
        function output = system(obj,command,sudo)
            % output = system(hw,command,<sudo>) executes the command on
            % the hardware and returns the resulting output. If the
            % optional input, 'sudo', is specified as the third argument,
            % the command is executed as super user.
            i_validateCharArg(command,'command');
            if nargin > 2
                sudo = validatestring(sudo,{'sudo'},'','sudo');
                sudo = [sudo, ' '];
            else
                sudo = '';
            end
            
            % Execute command on the remote host via SSH
            try
                output = execute(obj.Ssh,[sudo command]);
            catch ME
                throwAsCaller(ME);
            end
        end
        
        %% putFile
        function putFile(obj,localFile,remoteFile,throwEx)
            % PUTFILE(hw,localFile,remoteFile) copies the localFile on the
            % host computer to the remoteFile on the hardware. Path names
            % and wildcards may be used to specify the localFile. The
            % remoteFile argument must either be a directory or a name
            % representing a single file, depending on the localFile
            % specification.
            %
            % The remoteFile argument is optional. If not specified, the
            % localFile is copied to the user's home directory.
            %
            % See also dir, getFile and putFile.

            i_validateCharArg(localFile,'localFile');

            if nargin > 2
                i_validateCharArg(remoteFile,'remoteFile');                
                
                % Run an echo on the target device to expand ~ and other
                % variables, such as $HOME
                remoteFile = strtrim(execute(obj.Ssh,['echo ' remoteFile],false));                
            else
                % Default to user's home folder
                remoteFile = strtrim(execute(obj.Ssh,'echo ~',false));
            end
            remoteFile = i_handleSpaces(remoteFile);
            
            if (nargin < 4)
                throwEx = true;
            end
            
            % Retrieve local file information
            locFileInfo = dir(localFile);
            if numel(locFileInfo) == 0 && throwEx
                error('shared_linuxservices:utils:PutFileError',...
                    'Cannot identify %s. No such file or directory.',localFile);
            end
            
            % Determine remoteFile type
            remoteFile = strtrim(remoteFile);
            remFileIsDir = i_exist(obj.Ssh,remoteFile,'dir');
            remFileIsFile = i_exist(obj.Ssh,remoteFile,'file');
            if numel(locFileInfo) > 1 && ~remFileIsDir && remFileIsFile
                error('shared_linuxservices:utils:GetFileError',...
                    ['Cannot identify %s. No such directory. ',...
                    'When localFile argument specifies multiple files or a directory, ', ...
                    'the remoteFile argument must be an existing directory.'],remoteFile);
            elseif numel(locFileInfo) > 1 && ~remFileIsDir && ~remFileIsFile
                i_mkRemoteDir(obj.Ssh,remoteFile);
            end
            remFileIsDir = i_exist(obj.Ssh,remoteFile,'dir');
            
            % Copy each file/directory recursively
            for k = 1:numel(locFileInfo)
                thisFile = locFileInfo(k);
                if thisFile.isdir
                    if ~isequal(thisFile.name,'.') && ~isequal(thisFile.name,'..')
                        newFolder = i_fullLnxFile(remoteFile,thisFile.name);
                        i_mkRemoteDir(obj.Ssh,newFolder);
                        putFile(obj,...
                            fullfile(thisFile.folder,thisFile.name),...
                            newFolder,...
                            false);
                    end
                else
                    try
                        if remFileIsDir
                            remFileName = i_fullLnxFile(remoteFile,thisFile.name);
                        else
                            remFileName = remoteFile;
                        end
                        scpPutFile(obj.Ssh,...
                            fullfile(thisFile.folder,thisFile.name),...
                            remFileName);
                    catch ME
                        throwAsCaller(ME);
                    end
                end
            end
        end
        
        %% getFile
        function getFile(obj,remoteFile,localFile,throwEx)
            % GETFILE(hw,remoteFile,localFile) copies remoteFile on the
            % hardware to the localFile in the host computer. Path names
            % and wildcards may be used to specify the remoteFile. The
            % localFile argument must either be a directory or a name
            % representing a single file, depending on the remoteFile
            % specification.
            %
            % The localFile argument is optional. If not specified, the
            % remoteFile is copied to the current directory.
            %
            % See also dir, putFile and system.
            i_validateCharArg(remoteFile,'remoteFile');
            remoteFile = i_handleSpaces(remoteFile);
            if (nargin < 3)
                localFile = pwd;
            else
                i_validateCharArg(localFile,'localFile');
            end
            
            if (nargin < 4)
                throwEx = true;
            end
            
            % Copy remote file(s) to local file system
            remFileInfo = dir(obj,remoteFile);
            if numel(remFileInfo) == 0 && throwEx
                error('shared_linuxservices:utils:GetFileError',...
                    'Cannot identify %s. No such file or directory.',remoteFile);
            end
            
            % Determine localFile type
            localFile = strtrim(localFile);
            if numel(remFileInfo) > 1 && ~exist(localFile,'dir') ...
                    && exist(localFile,'file')
                error('shared_linuxservices:utils:GetFileError',...
                    ['Cannot identify %s. No such directory. ',...
                    'When remoteFile argument specifies multiple files or a directory, ', ...
                    'the localFile argument must be an existing directory.'],localFile);
            elseif numel(remFileInfo) > 1 && ~exist(localFile,'dir') ...
                    && ~exist(localFile,'file')
                i_mkdir(localFile);
            end
            
            % Copy files recursively
            for k = 1:numel(remFileInfo)
                thisFile = remFileInfo(k);
                if thisFile.isdir
                    % recursively copy the directory
                    if ~isequal(thisFile.name,'.') && ~isequal(thisFile.name,'..')
                        newDir = fullfile(localFile,thisFile.name);
                        i_mkdir(newDir);
                        getFile(obj,...
                            i_fullLnxFile(thisFile.folder,thisFile.name),...
                            newDir,...
                            false); % Don't throw an error if file does not exist
                    end
                else
                    try
                        if isdir(localFile)
                            localFileName = fullfile(localFile,thisFile.name);
                        else
                            localFileName = localFile;
                        end
                        scpGetFile(obj.Ssh,...
                            i_fullLnxFile(thisFile.folder,thisFile.name),...
                            localFileName);
                    catch ME
                        throwAsCaller(ME);
                    end
                end
            end
        end
        
        %% dir
        function d = dir(obj,fileSpec)
            %dir List directory.
            %     dir directory_name lists the files in a directory. Pathnames and
            %     asterisk wildcards may be used. A single asterisk in the path touching
            %     only file separators will represent exactly one directory name. A
            %     single asterisk at the end of an input will represent any filename. An
            %     asterisk followed or preceded by characters will resolve to zero or
            %     more characters. A double asterisk can only be used in the path and
            %     will represent zero or more directory names. It cannot touch a character
            %     other than a file separator. For example, dir *.m lists all files with
            %     a .m extension in the current directory. dir */*.m lists all files with
            %     a .m extension exactly one directory under the current directory.
            %     dir **/*.m lists all files with a .m extension zero or more directories
            %     under the current directory.
            %
            %     D = dir(hw,'directory_name') returns the results in an M-by-1
            %     structure with the fields:
            %         name        -- Filename
            %         folder      -- Absolute path
            %         bytes       -- Number of bytes allocated to the file
            %         isdir       -- 1 if name is a directory and 0 if not
            %
            %     See also getFile, putFile and system.
            i_validateCharArg(fileSpec,'fileSpec');
            fileSpec = i_fullLnxFile(strtrim(fileSpec));
            fileSpec = i_handleSpaces(fileSpec);
            if fileSpec(1) ~= '/' && fileSpec(1) ~= '~'
                rootDir = strtrim(system(obj,'echo ~'));
            else
                rootDir = '';
            end
            rootDir = i_handleSpaces(rootDir);
            d = [];
            
            % Stat the file spec. Dereference symbolic links
            out = execute(obj.Ssh,['stat -L --printf=''%n:&:%F:&:%s:&:%y\n'' ' fileSpec],false);
            if isempty(out)
                return;
            end
            
            % We treat directories differently
            tmp = regexp(strtrim(out),'\n','split');
            if numel(tmp) == 1
                tmp1 = regexp(tmp{1},':&:','split');
                if strfind(tmp1{2},'directory')
                    d = i_dirDirectory(obj.Ssh,tmp1{1});
                    return;
                end
            end
            for k = 1:numel(tmp)
                tmp1 = regexp(tmp{k},':&:','split');
                [p,n,ext] = fileparts(tmp1{1});
                d(end+1,1).name = [n ext]; %#ok<AGROW>
                d(end).folder = fileparts(i_fullLnxFile(rootDir,p,[n ext]));
                if strfind(tmp1{2},'directory')
                    d(end).isdir = true;
                    d(end).bytes = 0;
                else
                    d(end).isdir = false;
                    d(end).bytes = str2double(tmp1{3});
                end
            end
        end
        
        %% deleteFile
        function deleteFile(obj,fileName)
            % DELETEFILE(hw,fileName) deletes a file on the hardware.
            i_validateCharArg(fileName,'fileName');
            fileName = i_handleSpaces(fileName);
            
            try
                execute(obj.Ssh,['rm -fr ' fileName]);
            catch ME
                throwAsCaller(ME);
            end
        end
    end
end

% Internal functions
function i_validateCharArg(file,argName)
validateattributes(file,{'char'},{'nonempty','row'},'',argName);
end

function file = i_fullLnxFile(varargin)
% Convert paths to Linux convention.

% Replace backslash with forward slash (if the user provides windows path
% separators), but ignore escaped spaces, since
% that backslash is used as an escape character, not as a path separator.
% Escaped spaces might occur if the path contains file or folder names with
% spaces.
file = regexprep(varargin{1}, '\\[^ ]', '/');

for i = 2:nargin
    file = [file, '/', varargin{i}]; %#ok<AGROW>
end
file = strrep(file, '//', '/');
file = regexprep(file, '/$', '');  %remove trailing slash
end

function d = i_dirDirectory(ssh,directory)
d = [];
directory = i_handleSpaces(strtrim(directory));
out = execute(ssh,['stat -L --printf=''%n:&:%F:&:%s\n'' ' ...
    directory '/.* ' directory '/*'],false);
if isempty(out)
    return;
end
tmp = regexp(strtrim(out),'\n','split');
for k = 1:numel(tmp)
    tmp1 = regexp(tmp{k},':&:','split');
    if numel(tmp1) < 3
        break;
    end
    [p,n,ext] = fileparts(tmp1{1});
    d(end+1).name = [n ext]; %#ok<AGROW>
    d(end).folder = p;
    if strfind(tmp1{2},'directory')
        d(end).isdir = true;
        d(end).bytes = 0;
    else
        d(end).isdir = false;
        d(end).bytes = str2double(tmp1{3});
    end
end
end

function i_mkdir(p)
[s,msg,msgid] = mkdir(p);
if s ~= 0 && ~isequal(msgid,'MATLAB:MKDIR:DirectoryExists')
    error(msgid,msg);
end
end

function ret = i_exist(ssh,fileSpec,fileType)
% Replacement for exist for file on the remote file system
ret = 0;
fileSpec = i_handleSpaces(fileSpec);
switch fileType
    case 'dir'
        out = execute(ssh,['[ -d ' fileSpec ' ] && echo 1 || echo 0'],false);
        if isequal(strtrim(out),'1')
            ret = 7;
        end
    case 'file'
        out = execute(ssh,['[ -f ' fileSpec ' ] && echo 1 || echo 0'],false);
        if isequal(strtrim(out),'1')
            ret = 2;
        end
end
end

function i_mkRemoteDir(ssh,remoteFile)
try
    remoteFile = i_handleSpaces(remoteFile);
    execute(ssh,['mkdir -p ' remoteFile]);
catch ME
    throwAsCaller(ME);
end
end

function escapedPath = i_handleSpaces(filePath)
%i_handleSpaces Handle spaces in file or folder path
%   In the system command that we send over SSH, spaces in the
%   path to a file or a folder need to be escaped with a backslash.

% Escape spaces. For example, this will change "file_w s" into "file_w\ s".
escapedPath = strrep(filePath, ' ', '\ ');

% If the spaces were already escaped, we should undo the
% double-escaping. Since this function might be called multiple times with
% the same names, we want to prevent double escapes. If the user calls
% i_handleSpaces with "file_w\ s", the return will be an unchanged 
% "file_w\ s".
escapedPath = strrep(escapedPath, '\\ ', '\ ');
end