Code covered by the BSD License  

Highlights from
Project Packaging interface

Project Packaging interface

by

 

15 Apr 2013 (Updated )

An interface and command line tool for creating an archive containing project files and dependencies

guiProjectPackager(varargin)
function varargout = guiProjectPackager(varargin)
% GUIPROJECTPACKAGER MATLAB code for guiProjectPackager.fig
%      GUIPROJECTPACKAGER, by itself, creates a new GUIPROJECTPACKAGER or raises the existing
%      singleton*.
%
%      H = GUIPROJECTPACKAGER returns the handle to a new GUIPROJECTPACKAGER or the handle to
%      the existing singleton*.
%
%      GUIPROJECTPACKAGER('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in GUIPROJECTPACKAGER.M with the given input arguments.
%
%      GUIPROJECTPACKAGER('Property','Value',...) creates a new GUIPROJECTPACKAGER or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before guiProjectPackager_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to guiProjectPackager_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help guiProjectPackager

% Last Modified by GUIDE v2.5 13-Apr-2013 18:09:41

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @guiProjectPackager_OpeningFcn, ...
                   'gui_OutputFcn',  @guiProjectPackager_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 guiProjectPackager is made visible.
function guiProjectPackager_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 guiProjectPackager (see VARARGIN)

%set up some elements for the gui

%%%%%%%%%%%%%%%%%%%%%%%%%%%% VERSION INFO %%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Ver 1:     First version of the GUI with basic functionality
%Ver 2:     Allow modification and deletion of existing definitions
%Ver 3:     Manually add dependencies that are not found by depfun
%Ver 4:
%Ver 5:
packVersion = 3;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%  BUILD INFO  %%%%%%%%%%%%%%%%%%%%%%%%%%%%
%build 0413.1:  initial build
%build 0413.2:  functional version that generates correct output
%build 0413.3:  modifications of the preferences: default location
%build 0413.4:  dependencies are expanded, default location updated
%build 0413.5:  
packBuild   = '0413.4';

guiroot  = strrep(mfilename('fullpath'), mfilename, '');
docroot  = fullfile(guiroot, 'doc');
preffile = fullfile(guiroot, 'ProjectPackager.prf');
if ispc()
    %home folder on windows platforms
    defloc = getenv('USERPROFILE');
else
    %home folder on linux and OSX platforms
    defloc = getenv('HOME');
end
%set the default location to the desktop
defloc = fullfile(defloc, 'Desktop');

%add all components to the appdata structure
setappdata(0, 'h_pack', gcf);
setappdata(gcf, 'guiroot', guiroot);
setappdata(gcf, 'docroot', docroot);
setappdata(gcf, 'preffile', preffile);
setappdata(gcf, 'defloc', defloc);
setappdata(gcf, 'packVersion', packVersion);
setappdata(gcf, 'packBuild', packBuild);
setappdata(gcf, 'handles', handles);

%create a reference to packageStruct and leave it empty
setappdata(gcf, 'packageStruct', []);
setappdata(gcf, 'packSession', '');

%save preference file if there is no file
if exist(preffile, 'file') ~= 2
    %no need to load the preferences afterwards, as iall the default values
    %are set in the opening function
    savePreferences();
else
    loadPreferences();
end
% Choose default command line output for guiProjectPackager
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

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



function savePreferences()
h = getappdata(0, 'h_pack');
packVersion = getappdata(h, 'packVersion');
packBuild   = getappdata(h, 'packBuild');
preffile    = getappdata(h, 'preffile');
defloc      = getappdata(h, 'defloc');
packSession = getappdata(h, 'packSession');

try
    %try to save the preffile
    save(preffile, 'packVersion', 'packBuild', 'defloc', 'packSession', '-mat');
catch me
    error(getReport(me, 'basic'));
end

function loadPreferences()
h = getappdata(0, 'h_pack');
preffile = getappdata(h, 'preffile');
packVersion = getappdata(h, 'packVersion');
try
    in = load(preffile, '-mat');
    if ~isfield(in, 'packVersion')
        %illegal file or missing info, create a new one by calling
        %savePreferences to create a fresh copy...
        savePreferences();
    else
        %compare the version in the file with the gui
        if packVersion > in.packVersion
            %the file is outdated, save a new one
            savePreferences();
        else
            setappdata(h, 'defloc', in.defloc);
            setappdata(h, 'packSession', in.packSession);
            %load the previous session
            if exist(in.packSession, 'file') == 2
                loadSession();
            end
        end
    end
catch me
    error(getReport(me, 'basic'));
end

function saveSession()
h = getappdata(0, 'h_pack');
%get the relevant parameters
defloc      = getappdata(h, 'defloc');
packSession = getappdata(h, 'packSession');
packVersion = getappdata(h, 'packVersion');

if isempty(packSession)
    %ask for a new session file
    [sessionfile, sessionpath] = uiputfile({'*.mat' 'Session file (*.mat)'}, 'Store the session file', defloc);
    if isempty(sessionpath)
        return;
    end
    packSession = fullfile(sessionpath, sessionfile);
    %store the session file location in appdata and in the pref file
    setappdata(h, 'packSession', packSession);
    savePreferences();
end

%store the session
packageStruct = getappdata(h, 'packageStruct');
try
    if ~isempty(packageStruct)
        %save the structure
        save(packSession, 'packageStruct', 'packVersion');
    end
catch me
    error(getReport(me, 'basic'));
end

function loadSession()
%load a previous packager session with project definitions
h = getappdata(0, 'h_pack');
handles = getappdata(h, 'handles');
defloc = getappdata(h, 'defloc');
packVersion = getappdata(h, 'packVersion');
packSession = getappdata(h, 'packSession');

if isempty(packSession)
    %ask the user for the package session
    [sessionfile, sessionpath] = uigetfile({'*.mat' 'Session file (*.mat)'}, 'Select a session file', defloc);
    
    if sessionpath == 0
        return;
    end
    
    sessionfile = fullfile(sessionpath, sessionfile);
else
    sessionfile = packSession;
end

if exist(sessionfile, 'file') ~= 2
    return;
else
    try
        in = load(sessionfile);
        if isfield(in, 'packVersion')
            if packVersion > in.packVersion
                %the file is outdated
                errordlg({'The selected file is outdated and can only be partially loaded.';
                            'Some functionality may be missing.'});
                
                %load the data anyway
                if isfield(in, 'packageStruct')
                    setappdata(h, 'packSession', sessionfile);
                    setappdata(h, 'packageStruct', in.packageStruct);
                else
                    return;
                end
            else
                %no version missmatch
                if isfield(in, 'packageStruct')
                    setappdata(h, 'packSession', sessionfile);
                    setappdata(h, 'packageStruct', in.packageStruct);
                else
                    return;
                end
            end
            %update the available list
            projectnames = {in.packageStruct.packagename};
            set(handles.list_available, 'String', projectnames);
        else
            %invalid file
            return;
        end
    catch me
        error(getReport(me, 'basic'));
    end
    savePreferences();
end

function cleanOnExit()
%save the session and preferences
savePreferences();
saveSession();
%remove the appdata
rmappdata(0, 'h_pack');


% --- Outputs from this function are returned to the command line.
function varargout = guiProjectPackager_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
varargout{1} = handles.output;


% --------------------------------------------------------------------
function menu_file_Callback(hObject, eventdata, handles)

% --------------------------------------------------------------------
function menu_help_Callback(hObject, eventdata, handles)

% --------------------------------------------------------------------
function menu_help_help_Callback(hObject, eventdata, handles)
h = getappdata(0, 'h_pack');
docroot = getappdata(h, 'docroot');
startpage = fullfile(docroot, 'index.html');
web(startpage, '-new', '-notoolbar');


% --------------------------------------------------------------------
function menu_help_about_Callback(hObject, eventdata, handles)
h = getappdata(0, 'h_pack');

packVersion = getappdata(h, 'packVersion');
packBuild   = getappdata(h, 'packBuild');

msg = { 'Project Packager'
       ['Version: ' num2str(packVersion)]
       ['Build: ' packBuild]
        ''
        'Developed by: Jurjen Broeke'
        'Contact: jurjen.broeke@cncr.vu.nl'
        ''
        'Vrije Universiteit (VU) and VU medical center Amsterdam '
        'Neuroscience Campus Amsterdam (NCA)'
        'Center for Neurogenomics and Cognitive Research (CNCR)'
        'Department of Functional Genomics'
        'De Boelelaan 1085'
        '1081HV Amsterdam, The Netherlands'
        'http://www.cncr.nl'
        '';
        'ProjectPackager is build to create distributable archives of'
        'matlab projects. It includes the main project files, as well'
        'as external functions required for the main project.'
        ''};

%display the about dialog
hAbout = msgbox(msg, 'About Project Packager', 'help');
uiwait(hAbout);

% --------------------------------------------------------------------
function menu_file_create_Callback(hObject, eventdata, handles)
%create a new package: add a project definition to the available list
h = getappdata(0, 'h_pack');

%get the current data structure
packageStruct = getappdata(h, 'packageStruct');

%show the interface for adding project details
hCreate = guiNewPackage();
uiwait(hCreate);

%get the updated data structure
newPackageStruct = getappdata(h, 'packageStruct');

if numel(newPackageStruct) > numel(packageStruct)
    %the structure was changed, update everything
    projname = {newPackageStruct.packagename};
    set(handles.list_available, 'String', projname);
end
%save the session
saveSession();


% --------------------------------------------------------------------
function menu_file_load_Callback(hObject, eventdata, handles)
loadSession();


% --------------------------------------------------------------------
function menu_file_save_Callback(hObject, eventdata, handles)
%save the current project definitions
saveSession();


% --------------------------------------------------------------------
function menu_file_exit_Callback(hObject, eventdata, handles)
hmain = getappdata(0, 'h_pack');
figure1_CloseRequestFcn(hmain, eventdata, handles);


% --- Executes on button press in button_add.
function button_add_Callback(hObject, eventdata, handles)
%get the selection from the available projects list
addlist   = get(handles.list_available, 'String');
addselect = get(handles.list_available, 'Value');

if isempty(addlist) || isempty(addselect)
    %nothing selected
    return;
end

%get the items to add to the build list
toAddList = addlist(addselect);
%remove the items from the add list
addlist(addselect) = [];

%get the items from the build list and add new items
bldlist = get(handles.list_build, 'String');
if ~isempty(bldlist)
    %there are already projects on the build list, add the new ones
    bldlist = [bldlist; toAddList];
else
    bldlist = toAddList;
end

%update both lists
set(handles.list_available, 'Value', 1);
set(handles.list_build, 'Value', 1);
set(handles.list_available, 'String', sort(addlist));
set(handles.list_build, 'String', sort(bldlist));

% --- Executes on button press in button_remove.
function button_remove_Callback(hObject, eventdata, handles)
%get the selection from the available projects list
addlist   = get(handles.list_build, 'String');
addselect = get(handles.list_build, 'Value');

if isempty(addlist) || isempty(addselect)
    %nothing selected
    return;
end

%get the items to add to the build list
toAddList = addlist(addselect);
%remove the items from the add list
addlist(addselect) = [];

%get the items from the build list and add new items
bldlist = get(handles.list_available, 'String');
bldlist = [bldlist; toAddList];

%update both lists
set(handles.list_available, 'Value', 1);
set(handles.list_build, 'Value', 1);
set(handles.list_build, 'String', sort(addlist));
set(handles.list_available, 'String', sort(bldlist));



% --- Executes on selection change in list_build.
function list_build_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function list_build_CreateFcn(hObject, eventdata, handles)
% 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


% --- Executes on button press in button_selected.
function button_selected_Callback(hObject, eventdata, handles)
%only build the selected projects
buildidx = get(handles.list_build, 'Value');
buildnames = get(handles.list_build, 'String');
if isempty(buildnames)
    return;
end

%filter the selected build names
buildnames = buildnames(buildidx);

h = getappdata(0, 'h_pack');
packSession = getappdata(h, 'packSession');
packageStruct = getappdata(h, 'packageStruct');
if isempty(packageStruct)
    %this is an error, should not occur
    return;
end
%check first for a session file
if isempty(packSession)
    %there is no session file yet, create one
    saveSession();
end

%get the relevant project definitions from the packageStruct

packagenames = {packageStruct.packagename};
buildindices = cell2mat(cellfun(@(a) strcmp(packagenames, a), buildnames, 'UniformOutput', false));
buildfilter  = any(buildindices, 1);

toBuild = packageStruct(buildfilter);

bOK = createPackages(toBuild);
if bOK
    %there were no problems
    for pkg=1:numel(packagenames)
        if buildfilter(pkg)
            packageStruct(pkg).lastbuild = datestr(now());
        end
    end
    setappdata(h, 'packageStruct', packageStruct);
    saveSession();
    helpdlg('Finished building the packages.', 'Completed');
else
    %there were problems
    errordlg('The building process was not completed succesfully.', 'Build error');
end

% --- Executes on button press in button_all.
function button_all_Callback(hObject, eventdata, handles)
%build all projects
h = getappdata(0, 'h_pack');
packSession = getappdata(h, 'packSession');
packageStruct = getappdata(h, 'packageStruct');

%check if there are any projects in the list for building
if isempty(get(handles.list_build, 'String'))
    %nothing selected for building
    return;
end

if isempty(packageStruct)
    %this is an error, should not occur
    return;
end
%check first for a session file
if isempty(packSession)
    %there is no session file yet, create one
    saveSession();
end

bOK = createPackages(packageStruct);
if bOK
    %there were no problems
    timestmp = datestr(now());
    for pkg = 1:numel(packageStruct)
        packageStruct(pkg).lastbuild = timestmp;
    end
    setappdata(h, 'packageStruct', packageStruct);
    saveSession();
    helpdlg('Finished building the packages', 'Completed');
else
    %there were problems
    errordlg('The building process was not completed succesfully', 'Build error');
end

function [bOK] = createPackages(packselection)
%create packages from the packselection
numprojects = numel(packselection);
bOK = false;

%create a temp folder for the projects
tempfolder = fullfile(tempdir, 'ProjectPackager');
if exist(tempfolder, 'dir') ~= 7
    %folder does not exist: create it
    try
        mkdir(tempfolder);
    catch me
        error(getReport(me, 'basic'));
    end
end

for pkg = 1:numprojects
    %create a package for each item
    projpack = packselection(pkg);
    
    %get the specifics for this project
    projectroot = projpack.rootdir;
    ignorelist  = projpack.ignorelist;
    ziplocation = projpack.archive;
    if isfield(projpack, 'extdepends')
        extdepends = projpack.extdepends;
    else
        extdepends = [];
    end
    
    %start the processing
    projfiles = collectProjectFiles(projectroot, ignorelist);
    if isempty(projfiles)
        %nothing to do here, perhaps generate an error?
        continue;   %for now, we'll skip this project
    end
    
    %create the folder structure in the temp folder for the project files
    try
        for f = 1:numel(projfiles)
            srce = projfiles{f};
            dest = strrep(srce, projectroot, '');
            dest = fullfile(tempfolder, dest);
            %check if dest folders exist
            [targetdir, ~, ~] = fileparts(dest);
            if exist(targetdir, 'dir') ~= 7
                mkdir(targetdir);
            end
            copyfile(srce, dest);
        end
    catch me
        error(getReport(me, 'basic'));
    end
    
    %get the dependencies for this project
    projdeps = checkProjectDependencies(projfiles, projectroot);
    if ~isempty(projdeps)
        %process the dependencies
        %copy the external dependencies to the tempdir
        destination = fullfile(tempfolder, 'dependencies');
        if exist(destination, 'dir') == 7
            %there was already a folder, empty it
            try
                delete(fullfile(destination, '*'));
            catch me
                error(getReport(me, 'basic'));
            end
            %now copy the files
            try
                for fd = 1:numel(projdeps)
                    fdep = projdeps{fd};
                    copyfile(fdep, destination);
                end
                %check for extra dependencies
                if ~isempty(extdepends)
                    for ed = 1:numel(extdepends)
                        edep = extdepends{ed};
                        copyfile(edep, fullfile(destination, 'extra'));
                    end
                end
            catch me
                error(getReport(me, 'basic'));
            end
        else
            try
                %no such folder, create and fill it
                mkdir(destination);
                for fd = 1:numel(projdeps)
                    fdep = projdeps{fd};
                    copyfile(fdep, destination);
                end
                %check for extra dependencies
                if ~isempty(extdepends)
                    for ed = 1:numel(extdepends)
                        edep = extdepends{ed};
                        copyfile(edep, fullfile(destination, 'extra'));
                    end
                end
            catch me
                error(getReport(me, 'basic'));
            end
        end
    end
    
    %create the zipfile
    try
        zip(ziplocation, fullfile(tempfolder, '*'));
        %remove the folders from the folder
        dirlist = dir(tempfolder);
        fnames  = {dirlist.name};
        dirfltr = [dirlist.isdir];
        fnames(1:2) = [];
        dirfltr(1:2) = [];
        
        %first remove the folders and their content
        rmFolders = fnames(dirfltr);
        cellfun(@(c) rmdir(fullfile(tempfolder, c), 's'), rmFolders);
        
        %second, delete the remaining files
        delete(fullfile(tempfolder, '*'));
    catch me
        error(getReport(me, 'basic'));
    end
end

%remove the tempfolder
try
    rmdir(tempfolder, 's');
    %everything was OK
    bOK = true;
catch me
    error(getReport(me, 'basic'));
end



% --- Executes on selection change in list_available.
function list_available_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function list_available_CreateFcn(hObject, eventdata, handles)
% 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 menu_file_prefs_Callback(hObject, eventdata, handles)
hmain = getappdata(0, 'h_pack');
defloc = getappdata(hmain, 'defloc');

%ask the user for a new default location for storing packages
new_defloc = uigetdir(defloc, 'Select a new default location for storage');

if new_defloc == 0
    return;
else
    %update the preferences
    setappdata(hmain, 'defloc', new_defloc);
    savePreferences();
end


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

%remove the appdata
cleanOnExit();

% Hint: delete(hObject) closes the figure
delete(hObject);


% --------------------------------------------------------------------
function menu_file_modify_Callback(hObject, eventdata, handles)
h = getappdata(0, 'h_pack');
packageStruct = getappdata(h, 'packageStruct');

if isempty(packageStruct)
    %nothing to do here
    return;
end
%get all the names from the pacakgeStruct
projnames = {packageStruct.packagename};

[selection, ok] = listdlg('ListString', projnames,...
                          'SelectionMode', 'single',...
                          'ListSize', [240, 300],...
                          'Name', 'Select project',...
                          'OKString', 'Modify');
if ok == 0
    %nothing to do: user canceled
    return;
end

hmod = guiModifyPackage(selection);
uiwait(hmod);

%update the interface to reflect the changes
updateInterface();


function updateInterface()
h = getappdata(0, 'h_pack');
handles = getappdata(h, 'handles');
packageStruct = getappdata(h, 'packageStruct');

%get all the names from the pacakgeStruct
projnames = {packageStruct.packagename};

%update the lists
set(handles.list_available, 'String', projnames);
set(handles.list_build, 'String', '');
set(handles.list_available, 'Value', 1);
set(handles.list_build, 'Value', 1);

Contact us