Code covered by the BSD License  

Highlights from
Subversion GUI

image thumbnail
from Subversion GUI by Jonas
GUI for command-line subversion client

svnGUI(varargin)
function varargout = svnGUI(varargin)
%SVNGUI provides a GUI for the subversion version control system
%
% For this to work, you need a command-line subversion client installed on
% your system. If the server hosting the code uses certificates, you have
% to accept it on the command line, otherwise Matlab hangs. If you know how
% to do that from within Matlab, please let me know.
%
% The GUI allows you to update, commit, add, and assess the difference
% between files that are under version control
%
% svnGUI assumes that the code is in a subdirectory 'matlab' of a directory
% specified in the environment variable MATLABHOME (or HOME, if MATLABHOME
% has not been set. Jump to the line indicated by the cell header to change
% this, if necessary.
%
% Note that svnGUI is only committing code from directories where you
% entered a message that is different from noCommit. In other words, if
% there have been changes for two directories, but you only write a comment
% for the first one, changes in the second directory are not committed.
%
%
% (c) Jonas Dorn, 29-Mar-2009

% Last Modified by GUIDE v2.5 02-Apr-2009 21:44:50




% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @svnGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @svnGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before svnGUI is made visible.
function svnGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to svnGUI (see VARARGIN)


% Choose default command line output for svnGUI
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% check input arguments
if length(varargin) > 0 && ~isempty(varargin{1})
    if existDir(varargin{1});
        root = varargin{1};
    elseif strcmpi(varargin{1},'ask')
        root = uigetdir('Please choose code top-directory');
        if root==0
            root = [];
        end
    else
        error('unrecognized option for input directory (%s)',varargin{1});
    end
else
    root = [];
end

initGUI(handles,root);

% UIWAIT makes svnGUI wait for user response (see UIRESUME)
% uiwait(handles.svnGUI);


% --- Outputs from this function are returned to the command line.
function varargout = svnGUI_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
if ~isempty(handles)
    varargout{1} = handles.output;
end


% --- Executes on selection change in svng_topDir.
function svng_topDir_Callback(hObject, eventdata, handles)
% hObject    handle to svng_topDir (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns svng_topDir contents as cell array
%        contents{get(hObject,'Value')} returns selected item from svng_topDir

% on changing directory, change text in both boxes
dirNum = get(hObject,'Value');

set(handles.svng_changeTxt,'String',handles.changeList{dirNum},'Value',1);
set(handles.svng_messageTxt,'String',handles.messageList{dirNum});

guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function svng_topDir_CreateFcn(hObject, eventdata, handles)
% hObject    handle to svng_topDir (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on selection change in svng_changeTxt.
function svng_changeTxt_Callback(hObject, eventdata, handles)
% hObject    handle to svng_changeTxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns svng_changeTxt contents as cell array
%        contents{get(hObject,'Value')} returns selected item from svng_changeTxt


% --- Executes during object creation, after setting all properties.
function svng_changeTxt_CreateFcn(hObject, eventdata, handles)
% hObject    handle to svng_changeTxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: listbox controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function svng_messageTxt_Callback(hObject, eventdata, handles)
% hObject    handle to svng_messageTxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of svng_messageTxt as text
%        str2double(get(hObject,'String')) returns contents of svng_messageTxt as a double

% store messageTxt in messageList
dirNum = get(handles.svng_topDir,'Value');
messageTxt = get(hObject,'String');
handles.messageList{dirNum} = messageTxt;
if strcmpi(messageTxt,'nocommit')
    handles.todo(dirNum) = false;
else
    handles.todo(dirNum) = true;
end

guidata(hObject,handles);


% --- Executes during object creation, after setting all properties.
function svng_messageTxt_CreateFcn(hObject, eventdata, handles)
% hObject    handle to svng_messageTxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in svng_cancel.
function svng_cancel_Callback(hObject, eventdata, handles)
% hObject    handle to svng_cancel (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% if any todo, ask user for confirmation
if any(handles.todo)
    answer = questdlg('You have entered at least one message. Do you really want to quit?','Are you sure?','Yes','No','No');
    if ~strcmp(answer,'Yes')
        return
    end
end

% quit without committing
cleanup(handles)
delete(handles.svnGUI)

% --- Executes on button press in svng_OK.
function svng_OK_Callback(hObject, eventdata, handles)
% hObject    handle to svng_OK (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

topDirList = get(handles.svng_topDir,'String');

% loop through todo, commit
for dirNum = find(handles.todo)'
    % get message
    msg = handles.messageList{dirNum};
    % convert msg so that there will be newLines in the svn log later
    nLines = size(msg,1);
    if nLines == 1
        newLines = ',[]'; % done
    else
        % prepare msg such that we can add char(10) where there was a line
        % break before
        msg = [msg,repmat('%s',nLines,1)];
        msg = msg';
        msg = msg(:)';
        msg = regexprep(msg,'\s{3,}',''); % remove superfluous whitespace
        newLines = repmat(', char(10)',1,nLines);
    end
    % if there apostrophes, the code fails b/c of sprintf
    msg = regexprep(msg,'''','''''');
    msg = regexprep(msg,'%','%%');
    eval(['[ status, err ] = system( sprintf(''svn commit ',regexprep(fullfile(handles.root,topDirList{dirNum}),'\\','\\\\'),' -m "',msg ,'"''',newLines,') );' ] );
    disp(err)
end

% quit
cleanup(handles);
delete(handles.svnGUI);

% initialize GUI
function handles = initGUI(handles,root)

% --- to open, make two lists
% topDirList, which is going to populate the pulldown
% changeList, which is the list of changes for each topDir



%% change here to find your code directory

% Get environment variables MATLABHOME 
if (nargin < 2 || isempty(root)) && (~isfield(handles,'root') || isempty(handles.root))
    MATLABHOME = getenv( 'MATLABHOME' );
    if isempty( MATLABHOME )
        MATLABHOME = getenv( 'HOME' );
        if isempty( MATLABHOME )
            h = errordlg('Error: environment variable ''MATLABHOME'' or ''HOME'' not set.');
            uiwait(h);
            cleanup(handles)
            delete(handles.svnGUI);
            return
        end
    end
    
    % Check for the existance of the subdirectory 'matlab'
    matlabSubdir = fullfile( MATLABHOME, 'matlab' );
    if ~existDir(matlabSubdir)
        h = errordlg(sprintf('Error: subdirectory %s does not exist.',matlabSubdir));
        uiwait(h);
        cleanup(handles)
        delete(handles.svnGUI);
        return
    end
    
else
    if nargin > 1 && ~isempty(root)
        matlabSubdir = root;
    else
        matlabSubdir = handles.root;
    end
end

% Get list of subdirectories
subdirs = dir( matlabSubdir );
subdirs( [ subdirs.isdir ] == 0 ) = [];

% Loop through directories that are svn working copies
counter = 0;
ccounter = 0;

nSubdirs = numel( subdirs );
[topDirList,changeList,svnDirList] = deal(cell(nSubdirs,1));

for i = 1 : nSubdirs
        
    if strcmp( subdirs( i ).name, '.' ) || strcmp( subdirs( i ).name, '..' ) 
        continue;
    end
    
    % do not check directories to which certain users do not have access
    if strcmp(getenv('COMPUTERNAME'),'MADP05-IRIC') && ~strcmp(getenv('USERNAME'),'p0877743') && ...
        (strcmp(subdirs(i).name,'newFunctions') || strcmp(subdirs(i).name,'chromdyn-tsri'))
        continue
    end

    % Run an svn status.
    eval(['[ status, err ] = system( ''svn status "',fullfile(matlabSubdir,subdirs( i ).name),'"'' );' ] );

    % Skip directories that are not working copies
    if findstr( err, 'is not a working copy' )
        continue;
    end
    
    % add to svnDirList
    counter = counter + 1;
    svnDirList{counter} = subdirs( i ).name;
    

    % good directory. Store if something needs committing
    if ~isempty(err)
        ccounter = ccounter + 1;
        topDirList{ ccounter } = subdirs( i ).name;
        % do not store the full path in changeList
        chl = strrep(err,matlabSubdir,'');
        % make sure multiline text breaks in box
        rr = regexp(chl,'([^\n]+)\n','tokens');
        changeList{ ccounter } = cat(1,rr{:});
    end
    
end

% check whether there is anything to do
if ccounter == 0
    h = errordlg('There has been no change since the last commit','svn - nothing to do');
    uiwait(h)
    delete(handles.svnGUI)
    return
end

% clip lists
topDirList(ccounter+1:end) = [];
changeList(ccounter+1:end) = [];
svnDirList(counter+1:end) = [];

% set updateDirList
if counter > 0
set(handles.svng_updateDir,'String',[{'all'};svnDirList],'Enable','on');
set(handles.svng_update,'Enable','on')
else
    set(handles.svng_updateDir,'Enable','off')
    set(handles.svng_update,'Enable','off')
end
set(handles.svng_topDir,'String',topDirList);

% write text to listbox
set(handles.svng_changeTxt,'String',changeList{1});

% remember changeList
handles.changeList = changeList;

% init messageList
handles.messageList = cell(size(changeList));
% set a noCommit flag
[handles.messageList{:}] = deal('noCommit');

% init todoList
handles.todo = false(size(changeList));

% store root
handles.root = matlabSubdir;

% init tmpFiles
handles.tmpFiles = [];


% and store handles
guidata(handles.svnGUI,handles)


% --- Executes on button press in svng_update.
function svng_update_Callback(hObject, eventdata, handles)
% hObject    handle to svng_update (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)


% update the selected directory
dir2update = get(handles.svng_updateDir,'Value');
dirList = get(handles.svng_updateDir,'String');
dirList(1) = [];
if dir2update == 1
    % keep entire dirList
else
    dirList = dirList(dir2update-1);
end

% loop through directories to update
for dirName = dirList(:)'
    fprintf('Updating %s...\n',dirName{1})
eval(['[ status, err ] = system( ''svn update "',fullfile(handles.root,dirName{1}),'"'' );' ] );
fprintf('\b\b\b\b\n%s\n',err);
end


% --- Executes on button press in svng_diff.
function svng_diff_Callback(hObject, eventdata, handles)
% hObject    handle to svng_diff (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% for diff-ing, make a copy of the file, revert the original, copy that,
% too, and copy back. Then use visDiff on the two files. Remove the
% temporary files in the end. 

% check for the file. We want only one selection
selection = get(handles.svng_changeTxt,'Value');
if length(selection) ~= 1
    h = errordlg('Please select only one single file for diff');
    uiwait(h);
    return
end
% get file
msg = get(handles.svng_changeTxt,'String');
txt = msg{selection};
txt = regexprep(txt,'(.\s+)\S','');
[p,n,e] = fileparts(txt);

% make sure there is a tmp dir
tmpDir = fullfile(handles.root,'svnGUI_tmp');
if ~existDir(tmpDir)
    mkdir(tmpDir);
end

% copy file
originalFile = fullfile(handles.root,txt);
newFile = fullfile(tmpDir,[n,'_new',e]);
copyfile(originalFile,newFile);

% revert original
eval(['[status,err] = system( '' svn revert "',originalFile,'"'' );' ] );

% copy file
oldFile = fullfile(tmpDir,[n,'_old',e]);
copyfile(originalFile,oldFile);

% copy back
copyfile(newFile,originalFile);

% visualize
visdiff(oldFile,newFile,80);

% remember tmp files
handles.tmpFiles = [handles.tmpFiles;{oldFile;newFile}];
guidata(hObject,handles);

% --- Executes on button press in svng_add.
function svng_add_Callback(hObject, eventdata, handles)
% hObject    handle to svng_add (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% loop through files in messageTxt and check for question mark
msg = get(handles.svng_changeTxt,'String');
% only take selected items
selection = get(handles.svng_changeTxt,'Value');
if isempty(selection)
    h = errordlg('Please select files to be added');
    uiwait(h);
    return
else
    msg = msg(selection);
end
for i = 1:size(msg,1)
    txt = msg{i};
    if strcmp(txt(1),'?')
        txt = regexprep(txt,'(\?\s+)\S','');
        eval(['[ status, err ] = system( ''svn add "',fullfile(handles.root,txt),'"'' );' ] );
        disp(err);
    end
end

% re-init the GUI
initGUI(handles);

% % try to add all open files in the editor 
% 
% % read open editor files
% fileListObj = com.mathworks.mlservices.MLEditorServices;
% fileList = char(fileListObj.builtinGetOpenDocumentNames);
% 
% for i=1:size(fileList,1)
%     % only try to add files that are on the matlab-code-path
%     if any(strmatch(handles.root,fileList(i,:)))
%     try
%         eval(['[ status, err ] = system( ''svn add "',fileList(i,:),'"'' );' ] );
%     end
%     end
% end
% 
% % re-init the GUI
% initGUI(handles);


% --- Executes on selection change in svng_updateDir.
function svng_updateDir_Callback(hObject, eventdata, handles)
% hObject    handle to svng_updateDir (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = get(hObject,'String') returns svng_updateDir contents as cell array
%        contents{get(hObject,'Value')} returns selected item from svng_updateDir


% --- Executes during object creation, after setting all properties.
function svng_updateDir_CreateFcn(hObject, eventdata, handles)
% hObject    handle to svng_updateDir (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% cleanup
function cleanup(handles)
% to be called before deleting the handle to the GUI

% check whether we may be initializing
if isfield(handles,'tmpFiles') && isfield(handles,'root')

% fileList = handles.tmpFiles;
% for i=1:length(fileList)
%     delete(fileList{i})
% end
tmpDir = fullfile(handles.root,'svnGUI_tmp');
if existDir(tmpDir)
    rmdir(tmpDir,'s')
end

end

% --- Executes when user attempts to close svnGUI.
function svnGUI_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to svnGUI (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% call cancel
svng_cancel_Callback(hObject,eventdata,handles);




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function success = existDir(dirName)
%EXISTDIR checks whether a directory exists
%
% SYNOPSIS: success = existDir(dirName)
%
% INPUT dirName: string or cell array of strings containing possible
%                directoryNames (either relative to current directory or
%                absolute paths
%
% OUTPUT success: logical 1 (or 0) if dirName is a directory (or not)
%
% REMARKS ExistDir performs the same function as exist(dirName,'dir'), but
%         it is much faster.
%
% created with MATLAB ver.: 7.7.0.471 (R2008b) on Windows_NT
%
% created by: Jonas Dorn
% DATE: 17-Nov-2008
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Test input
if nargin < 1
    error('please supply directory name to existDir')
end

% check for cell array
if iscell(dirName)
    success = cellfun(@existDir,dirName);
else
    % try to cd to the directory. If it works, it's a directory!
    success = false;
    try %#ok<TRYNC>
        oldDir = cd(dirName);
        cd(oldDir);
        % if we arrive here without problem, it's a success
        success = true;
    % catch
        % it's not an accessible directory
    end
end

Contact us at files@mathworks.com