1 new changeset in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/dbd80b36e0ba/ changeset: dbd80b36e0ba user: greg date: 2011-06-21 15:38:06 summary: Add the ability to select files for deletion from the repository using the built-in file browser. Any number of selected files will be deleted. Selecting a folder will delete all of it's contents. Fixes issue # 584. affected #: 11 files (8.7 KB) --- a/lib/galaxy/webapps/community/controllers/common.py Mon Jun 20 17:02:51 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/common.py Tue Jun 21 09:38:06 2011 -0400 @@ -1,10 +1,11 @@ -import tarfile +import os, tarfile, tempfile, shutil from galaxy.web.base.controller import * from galaxy.webapps.community import model from galaxy.model.orm import * from galaxy.web.framework.helpers import time_ago, iff, grids from galaxy.web.form_builder import SelectField from galaxy.model.item_attrs import UsesItemRatings +from mercurial import hg, ui import logging log = logging.getLogger( __name__ ) @@ -58,3 +59,55 @@ def get_user( trans, id ): """Get a user from the database""" return trans.sa_session.query( trans.model.User ).get( trans.security.decode_id( id ) ) +def hg_add( trans, current_working_dir, cloned_repo_dir ): + # Add files to a cloned repository. If they're already tracked, this should do nothing. + os.chdir( cloned_repo_dir ) + os.system( 'hg add > /dev/null 2>&1' ) + os.chdir( current_working_dir ) +def hg_clone( trans, repository, current_working_dir ): + # Make a clone of a repository in a temporary location. + repo_dir = repository.repo_path + tmp_dir = tempfile.mkdtemp() + tmp_archive_dir = os.path.join( tmp_dir, 'tmp_archive_dir' ) + if not os.path.exists( tmp_archive_dir ): + os.makedirs( tmp_archive_dir ) + cmd = "hg clone %s > /dev/null 2>&1" % os.path.abspath( repo_dir ) + os.chdir( tmp_archive_dir ) + os.system( cmd ) + os.chdir( current_working_dir ) + cloned_repo_dir = os.path.join( tmp_archive_dir, 'repo_%d' % repository.id ) + return tmp_dir, cloned_repo_dir +def hg_commit( commit_message, current_working_dir, cloned_repo_dir ): + # Commit a change set to a cloned repository. + if not commit_message: + commit_message = "No commit message" + os.chdir( cloned_repo_dir ) + os.system( "hg commit -m '%s' > /dev/null 2>&1" % commit_message ) + os.chdir( current_working_dir ) +def hg_push( trans, repository, current_working_dir, cloned_repo_dir ): + # Push a change set from a cloned repository to a master repository. + repo_dir = repository.repo_path + repo = hg.repository( ui.ui(), repo_dir ) + # We want these change sets to be associated with the owner of the repository, so we'll + # set the HGUSER environment variable accordingly. + os.environ[ 'HGUSER' ] = trans.user.username + cmd = "hg push %s > /dev/null 2>&1" % os.path.abspath( repo_dir ) + os.chdir( cloned_repo_dir ) + os.system( cmd ) + os.chdir( current_working_dir ) +def hg_remove( file_path, current_working_dir, cloned_repo_dir ): + # Remove a file path from a cloned repository. Since mercurial doesn't track + # directories (only files), directories are automatically removed when they + # become empty. + abs_file_path = os.path.join( cloned_repo_dir, file_path ) + if os.path.exists( abs_file_path ): + cmd = 'hg remove %s > /dev/null 2>&1' % file_path + os.chdir( cloned_repo_dir ) + os.system( cmd ) + os.chdir( current_working_dir ) +def update_for_browsing( repository, current_working_dir ): + # Make a copy of a repository's files for browsing. + repo_dir = repository.repo_path + os.chdir( repo_dir ) + os.system( 'hg update > /dev/null 2>&1' ) + os.chdir( current_working_dir ) --- a/lib/galaxy/webapps/community/controllers/repository.py Mon Jun 20 17:02:51 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/repository.py Tue Jun 21 09:38:06 2011 -0400 @@ -378,7 +378,13 @@ return config.get( "web", option ) raise Exception( "Repository %s missing allow_push entry under the [web] option in it's hgrc file." % repository.name ) def __set_allow_push( self, repository, usernames, remove_auth='' ): - # TODO: Use the mercurial api to handle this + """ + # TODO: Use the mercurial api to handle this, something like the following: + items = repo.ui.configitems( section, untrusted=False ) + push_section = repo.ui.config( 'hgrc', 'allow_push' ) + for XXX (in name you want to add): + repo.ui.updateconfig( section=extensions_section, name='XXX', value='YYY' ) + """ hgrc_file = os.path.abspath( os.path.join( repository.repo_path, ".hg", "hgrc" ) ) fh, fn = tempfile.mkstemp() for i, line in enumerate( open( hgrc_file ) ): @@ -403,6 +409,7 @@ params = util.Params( kwd ) message = util.restore_text( params.get( 'message', '' ) ) status = params.get( 'status', 'done' ) + commit_message = util.restore_text( params.get( 'commit_message', 'Deleted selected files' ) ) repository = get_repository( trans, id ) repo = hg.repository( ui.ui(), repository.repo_path ) # Our current support for browsing a repository requires copies of the @@ -416,6 +423,56 @@ return trans.fill_template( '/webapps/community/repository/browse_repository.mako', repo=repo, repository=repository, + commit_message=commit_message, + message=message, + status=status ) + @web.expose + def select_files_to_delete( self, trans, id, **kwd ): + params = util.Params( kwd ) + message = util.restore_text( params.get( 'message', '' ) ) + status = params.get( 'status', 'done' ) + commit_message = util.restore_text( params.get( 'commit_message', 'Deleted selected files' ) ) + repository = get_repository( trans, id ) + _ui = ui.ui() + repo_dir = repository.repo_path + repo = hg.repository( _ui, repo_dir ) + selected_files_to_delete = util.restore_text( params.get( 'selected_files_to_delete', '' ) ) + if params.get( 'select_files_to_delete_button', False ): + if selected_files_to_delete: + selected_files_to_delete = selected_files_to_delete.split( ',' ) + current_working_dir = os.getcwd() + # Get the current repository tip. + tip = repo[ 'tip' ] + # Clone the repository to a temporary location. + tmp_dir, cloned_repo_dir = hg_clone( trans, repository, current_working_dir ) + # Delete the selected files from the repository. + cloned_repo = hg.repository( _ui, cloned_repo_dir ) + for selected_file in selected_files_to_delete: + selected_file_path = selected_file.split( 'repo_%d' % repository.id )[ 1 ].lstrip( '/' ) + hg_remove( selected_file_path, current_working_dir, cloned_repo_dir ) + # Commit the change set. + if not commit_message: + commit_message = 'Deleted selected files' + hg_commit( commit_message, current_working_dir, cloned_repo_dir ) + # Push the change set from the cloned repository to the master repository. + hg_push( trans, repository, current_working_dir, cloned_repo_dir ) + # Remove the temporary directory containing the cloned repository. + shutil.rmtree( tmp_dir ) + # Update the repository files for browsing. + update_for_browsing( repository, current_working_dir ) + # Get the new repository tip. + repo = hg.repository( _ui, repo_dir ) + if tip != repo[ 'tip' ]: + message = "The selected files were deleted from the repository." + else: + message = 'No changes to repository.' + else: + message = "Select at least 1 file to delete from the repository before clicking <b>Delete selected files</b>." + status = "error" + return trans.fill_template( '/webapps/community/repository/browse_repository.mako', + repo=repo, + repository=repository, + commit_message=commit_message, message=message, status=status ) @web.expose --- a/lib/galaxy/webapps/community/controllers/upload.py Mon Jun 20 17:02:51 2011 -0400 +++ b/lib/galaxy/webapps/community/controllers/upload.py Tue Jun 21 09:38:06 2011 -0400 @@ -2,7 +2,7 @@ from galaxy.web.base.controller import * from galaxy.model.orm import * from galaxy.datatypes.checkers import * -from common import get_categories, get_repository +from common import get_categories, get_repository, hg_add, hg_clone, hg_commit, hg_push, update_for_browsing from mercurial import hg, ui log = logging.getLogger( __name__ ) @@ -139,12 +139,39 @@ # We have a repository that is not new (it contains files). if uncompress_file and ( isgzip or isbz2 ): uploaded_file_filename = self.uncompress( repository, uploaded_file_name, uploaded_file_filename, isgzip, isbz2 ) + # Get the current repository tip. + tip = repo[ 'tip' ] # Clone the repository to a temporary location. - tmp_dir, cloned_repo_dir = self.__hg_clone( trans, repository, repo_dir, current_working_dir ) + tmp_dir, cloned_repo_dir = hg_clone( trans, repository, current_working_dir ) # Move the uploaded files to the upload_point within the cloned repository. self.__move_to_upload_point( upload_point, uploaded_file, uploaded_file_name, uploaded_file_filename, cloned_repo_dir, istar, tar ) - # Commit and push the changes from the cloned repo to the master repo. - self.__hg_push( trans, repository, file_data.filename, uncompress_file, commit_message, current_working_dir, cloned_repo_dir, repo_dir, tmp_dir ) + # Add the files to the cloned repository. + hg_add( trans, current_working_dir, cloned_repo_dir ) + # Commit the files to the cloned repository. + if not commit_message: + commit_message = 'Uploaded' + hg_commit( commit_message, current_working_dir, cloned_repo_dir ) + # Push the changes from the cloned repository to the master repository. + hg_push( trans, repository, current_working_dir, cloned_repo_dir ) + # Remove the temporary directory containing the cloned repository. + shutil.rmtree( tmp_dir ) + # Update the repository files for browsing. + update_for_browsing( repository, current_working_dir ) + # Get the new repository tip. + repo = hg.repository( ui.ui(), repo_dir ) + if tip != repo[ 'tip' ]: + if uncompress_file: + uncompress_str = ' uncompressed and ' + else: + uncompress_str = ' ' + message = "The file '%s' has been successfully%suploaded to the repository." % ( uploaded_file_filename, uncompress_str ) + else: + message = 'No changes to repository.' + trans.response.send_redirect( web.url_for( controller='repository', + action='browse_repository', + commit_message='Deleted selected files', + message=message, + id=trans.security.encode_id( repository.id ) ) ) if ok: if files_to_commit: repo.dirstate.write() @@ -159,6 +186,7 @@ message = "The file '%s' has been successfully%suploaded to the repository." % ( uploaded_file_filename, uncompress_str ) trans.response.send_redirect( web.url_for( controller='repository', action='browse_repository', + commit_message='Deleted selected files', message=message, id=trans.security.encode_id( repository.id ) ) ) else: @@ -214,55 +242,6 @@ os.close( fd ) bzipped_file.close() shutil.move( uncompressed, uploaded_file_name ) - def __hg_clone( self, trans, repository, repo_dir, current_working_dir ): - tmp_dir = tempfile.mkdtemp() - tmp_archive_dir = os.path.join( tmp_dir, 'tmp_archive_dir' ) - if not os.path.exists( tmp_archive_dir ): - os.makedirs( tmp_archive_dir ) - # Make a clone of the repository in a temporary location - cmd = "hg clone %s > /dev/null 2>&1" % os.path.abspath( repo_dir ) - os.chdir( tmp_archive_dir ) - os.system( cmd ) - os.chdir( current_working_dir ) - cloned_repo_dir = os.path.join( tmp_archive_dir, 'repo_%d' % repository.id ) - return tmp_dir, cloned_repo_dir - def __hg_push( self, trans, repository, filename, uncompress_file, commit_message, current_working_dir, cloned_repo_dir, repo_dir, tmp_dir ): - repo = hg.repository( ui.ui(), repo_dir ) - tip = repo[ 'tip' ] - # We want these change sets to be associated with the owner of the repository, so we'll - # set the HGUSER environment variable accordingly. - os.environ[ 'HGUSER' ] = trans.user.username - # Add the file to the cloned repository. If it's already tracked, this should do nothing. - os.chdir( cloned_repo_dir ) - os.system( 'hg add > /dev/null 2>&1' ) - os.chdir( current_working_dir ) - os.chdir( cloned_repo_dir ) - # Commit the change set to the cloned repository - os.system( "hg commit -m '%s' > /dev/null 2>&1" % commit_message ) - os.chdir( current_working_dir ) - # Push the change set to the master repository - cmd = "hg push %s > /dev/null 2>&1" % os.path.abspath( repo_dir ) - os.chdir( cloned_repo_dir ) - os.system( cmd ) - os.chdir( current_working_dir ) - # Make a copy of the updated repository files for browsing. - os.chdir( repo_dir ) - os.system( 'hg update > /dev/null 2>&1' ) - os.chdir( current_working_dir ) - shutil.rmtree( tmp_dir ) - repo = hg.repository( ui.ui(), repo_dir ) - if tip != repo[ 'tip' ]: - if uncompress_file: - uncompress_str = ' uncompressed and ' - else: - uncompress_str = ' ' - message = "The file '%s' has been successfully%suploaded to the repository." % ( filename, uncompress_str ) - else: - message = 'No changes in uploaded files.' - trans.response.send_redirect( web.url_for( controller='repository', - action='browse_repository', - message=message, - id=trans.security.encode_id( repository.id ) ) ) def __move_to_upload_point( self, upload_point, uploaded_file, uploaded_file_name, uploaded_file_filename, cloned_repo_dir, istar, tar ): if upload_point is not None: if istar: --- a/templates/webapps/community/repository/browse_repository.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/browse_repository.mako Tue Jun 21 09:38:06 2011 -0400 @@ -93,17 +93,38 @@ %if can_browse_contents: <div class="toolForm"><div class="toolFormTitle">Browse ${repository.name}</div> - <div class="toolFormBody"> + <form name="select_files_to_delete" id="select_files_to_delete" action="${h.url_for( controller='repository', action='select_files_to_delete', id=trans.security.encode_id( repository.id ))}" method="post" ><div class="form-row" ><label>Contents:</label><div id="tree" > Loading... </div> + <div class="toolParamHelp" style="clear: both;"> + Click on a file to display it's contents below. You may delete files from the repository by clicking the check box next to each file and clicking the <b>Delete selected files</b> button. + </div> + <input id="selected_files_to_delete" name="selected_files_to_delete" type="hidden" value=""/> + </div> + <div class="form-row"> + <label>Message:</label> + <div class="form-row-input"> + %if commit_message: + <textarea name="commit_message" rows="3" cols="35">${commit_message}</textarea> + %else: + <textarea name="commit_message" rows="3" cols="35"></textarea> + %endif + </div> + <div class="toolParamHelp" style="clear: both;"> + This is the commit message for the mercurial change set that will be created if you delete selected files. + </div> + <div style="clear: both"></div> + </div> + <div class="form-row"> + <input type="submit" name="select_files_to_delete_button" value="Delete selected files"/></div><div class="form-row"><div id="file_contents" class="toolParamHelp" style="clear: both;background-color:#FAFAFA;"></div></div> - </div> + </form></div><p/> %endif --- a/templates/webapps/community/repository/common.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/common.mako Tue Jun 21 09:38:06 2011 -0400 @@ -35,11 +35,17 @@ // Display list of selected nodes var selNodes = dtnode.tree.getSelectedNodes(); // convert to title/key array - var selKeys = $.map(selNodes, function(node){ + var selKeys = $.map(selNodes, function(node) { return node.data.key; }); - // The following is used only in the upload form. - document.upload_form.upload_point.value = selKeys[0]; + if (document.forms["select_files_to_delete"]) { + // The following is used only ~/templates/webapps/community/repository/browse_repository.mako. + document.select_files_to_delete.selected_files_to_delete.value = selKeys.join(","); + } + // The following is used only in ~/templates/webapps/community/repository/upload.mako. + if (document.forms["upload_form"]) { + document.upload_form.upload_point.value = selKeys[0]; + } }, onActivate: function(dtnode) { var cell = $("#file_contents"); --- a/templates/webapps/community/repository/manage_repository.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/manage_repository.mako Tue Jun 21 09:38:06 2011 -0400 @@ -74,7 +74,7 @@ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a> %endif %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse repository</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse or delete repository files</a> %endif <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> --- a/templates/webapps/community/repository/rate_repository.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/rate_repository.mako Tue Jun 21 09:38:06 2011 -0400 @@ -79,7 +79,7 @@ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a> %endif %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse repository</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse or delete repository files</a> %endif <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> --- a/templates/webapps/community/repository/upload.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/upload.mako Tue Jun 21 09:38:06 2011 -0400 @@ -55,7 +55,7 @@ <a class="action-button" href="${h.url_for( controller='repository', action='view_changelog', id=trans.app.security.encode_id( repository.id ) )}">View change log</a> %endif %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse repository</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse or delete repository files</a> %endif </div></ul> @@ -106,7 +106,7 @@ %endif </div><div class="toolParamHelp" style="clear: both;"> - This is the commit message for the mercurial change set that will be created by this upload + This is the commit message for the mercurial change set that will be created by this upload. </div><div style="clear: both"></div></div> --- a/templates/webapps/community/repository/view_changelog.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/view_changelog.mako Tue Jun 21 09:38:06 2011 -0400 @@ -48,7 +48,7 @@ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a> %endif %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse repository</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse or delete repository files</a> %endif <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> --- a/templates/webapps/community/repository/view_changeset.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/view_changeset.mako Tue Jun 21 09:38:06 2011 -0400 @@ -52,7 +52,7 @@ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a> %endif %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse repository</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse or delete repository files</a> %endif <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> --- a/templates/webapps/community/repository/view_repository.mako Mon Jun 20 17:02:51 2011 -0400 +++ b/templates/webapps/community/repository/view_repository.mako Tue Jun 21 09:38:06 2011 -0400 @@ -74,7 +74,7 @@ <a class="action-button" href="${h.url_for( controller='repository', action='rate_repository', id=trans.app.security.encode_id( repository.id ) )}">Rate repository</a> %endif %if can_browse_contents: - <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse repository</a> + <a class="action-button" href="${h.url_for( controller='repository', action='browse_repository', id=trans.app.security.encode_id( repository.id ) )}">Browse or delete repository files</a> %endif <a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='gz' )}">Download as a .tar.gz file</a><a class="action-button" href="${h.url_for( controller='repository', action='download', repository_id=trans.app.security.encode_id( repository.id ), file_type='bz2' )}">Download as a .tar.bz2 file</a> Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.