Drupal & shell bookmarklet for updating modules 5 (updated – mulitple dbs, backup only option)

*Note: This is a follow up to the posts:

First off: here is the bookmarklet:
This first one is bare-bones; you get prompted for every var:
Install Mods Prompt

This next one needs to be customized to contain your directory and server data but then you don’t have to answer questions every time:
Install mods mysite
You can use http://subsimple.com/bookmarklets/jsbuilder.htm to edit the bookmarklet and set the defaults before saving it.

Now for the details:
I’ve refined the module install bookmarklets once again.
As with the previous versions: click the bookmarklet on a Drupal project page, pick the module and get the ssh script to install it.
Click the bookmarklet on your admin/reports/updates and get the code to install all the recommended updates.
This is tailored to work on our server and doesn’t work on our shell environment. Although it could with some modifications.
At this point you need to cut and paste the file and database backup lines independently because they each require passwords.
I’ll work towards a version that allows a single cut and paste.

Example:
Click the prompt bookmarklet it on the Views module page. Follow the prompts and you get this:

#ssh my-server-name
cd /my/server/path/; sudo tar -c --checkpoint my_drupal_site/ | gzip > /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.tar.gz;  ##Backed up files. Use this to restore: cd /my/server/path/; gzip -dc /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.tar.gz | tar -x --overwrite
#enter sudo password
mysqldump -u my_db_user_name -p my_db_name > /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.sql; ##BackupDB Use to restore: mysql --user=my_db_user_name -p my_db_name  /home/my_home_directory/drupal_backup/my_drupal_site_views_2-12-2010.tar.gz;  ##Backed up files. Use this to restore: cd /my/server/path/my_drupal_site/sites/all/modules/; gzip -dc /home/my_home_directory/drupal_backup/my_drupal_site_views_2-12-2010.tar.gz | tar -x
fi
wget http://ftp.drupal.org/files/projects/views-6.x-2.8.tar.gz
gzip -dc views-6.x-2.8.tar.gz | tar -x
rm views-6.x-2.8.tar.gz
ls -al

Breakdown of the example

table tr td {vertical-align:top;}
table tr:hover td {background-color:#9C3; color:white;}
table tr:hover td a {color:white; white-space:nowrap;}
table tr td table tr:hover td {background-color:white; color:#9C3;}
table td td table tr:hover td a {color:blue; white-space:nowrap;
table tr td a {white-space:nowrap;}

Command Explanation
#ssh my-server-name Connect to your server via ssh. Commented out to avoid ssh-ing while ssh-ing
cd /my/server/path/; Change to the directory that contains the drupal directory
sudo tar -c –checkpoint my_drupal_site/ | gzip > /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.tar.gz; ##Backed up files. Use this to restore: cd /my/server/path/; gzip -dc /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.tar.gz | tar -x –overwrite
Command Explanation
This line creates a back up of the site directory.
sudo I need privileges to do this. You may not
tar -c create an arive of the dir
–checkpoint get updates while the tar is being created
my_drupal_site/ the folder to be tar’d
| gzip > … Compress the archive using gzip into the following directory and with the datestamped file name. *this could be changed to use the archive feature of tar instead
# comment out the remainder of this line
#Backup files. Use this portion is included for convenience, so you can do a ‘history | grep backup’ and find your backup with the code needed to resurrect it.
cd /my/server/path/; change to the dir needed to restore.
gzip -dc -d=Decompress, -c=standard output
/home/my_home_dir…tar.gz the file that was saved previously
|tar -x untar (unzip) the file
–overwrite overwrite existing files. Valuable when untaring on to a different server (dev vs. prod)
#enter sudo password Comment to let you know which password you’re about to be prompted for
mysqldump -u my_db_user_name -p my_db_name > /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.sql; ##BackupDB Use to restore: mysql –user=my_db_user_name -p my_db_name < /home/my_home_directory/drupal_backup/my_drupal_site_2-12-2010.sql
Command Explaination
mysqldump created a back up of a database 
-u my_db_user_name. the database user name 
-p prompt for password
my_db_name the db name. *This can be a single string or a comma separated list of db’s
> /home/my_home_dir…sql; Save the output to this location with the date stamped name
# Comment out the remainder of this line 
#BackupDB. Use to restore this portion is included for convenience, so you can do a ‘history | grep backup’ and find your backup with the code needed to resurrect it.
mysql connect to mysql
–user=my_db_user_name db user name 
-p’ prompt for password
my_db_name database name
< /home/my_home_dir…sql The sql file you are restoring 
#enter db password Comment to let you know which password you’re about to be prompted for
cd /my/server/path/my_drupal_site/sites/all/modules/ Change to the modules dir.
if [ -d views ]
then
tar -c views/ | gzip > /home/my_home_directory/drupal_backup/my_drupal_site_views_2-12-2010.tar.gz; ##Backed up files. Use this to restore: cd /my/server/path/my_drupal_site/sites/all/modules/; gzip -dc /home/my_home_directory/drupal_backup/my_drupal_site_views_2-12-2010.tar.gz | tar -x
fi

This if statement checks if the module exists, and if so backs it up independantly.This can be handy for a quick restore and can be disabled.

if [ -d views ] test if the directory (-d) views exists
then If so then…
tar -c views/ | gzip > /home/my_home_directory/drupal_backup/my_drupal_site_views_2-12-2010.tar.gz; back it up using the same syntax as above
##Backed up files. Use this to restore: cd /my/server/path/my_drupal_site/sites/all/modules/; gzip -dc /home/my_home_directory/drupal_backup/my_drupal_site_views_2-12-2010.tar.gz | tar -x Reference code to restore the file if need be. Same as above
fi

End the if statement

wget http://ftp.drupal.org/files/projects/views-6.x-2.8.tar.gz Download module via FTP
gzip -dc views-6.x-2.8.tar.gz | tar -x un-gzip and un tar it
rm views-6.x-2.8.tar.gz remove it from the directory
ls -al list the directory contents with details

What’s old and what’s new:
Old:

  • The vars you might want to customize are just about all you need in the bookmarklet now.
    • In fact you don’t need those either.
    • Without them you will be prompted for each variable.
  • The code-base was moved to a central location so it’s easier to keep a bookmarklet for each site you manage with out updating several sets of code. I like this, as I need to be able to download updates and install modules for a 1/2 dozen different sites right now.
  • The jquery collection script and simple javascript single link options are both included in this version.
    • The bookmarklet automatically detects if you’re on admin/reports/updates and in that case, verifies that jQuery is available, then giving you the option to capture all the recommended updates. The default behavior is still to capture one update at a time with javascript.
  • The script ignores ‘project’ links on the module pages. So the first link you choose from is the latest download link.
  • The restoration code is included in a comment that follows the back up code for the directory and mysql

What’s New:

  • The tar command has been updated to ensure that relative directories are being used. So I’m cd ‘ing to the directory and then taring it locally now instead of including the full base path.
    Part of the reason for that is to accommodate restoring a backup into a different folder (on the dev server for example)
  • A backup/restore only option.
    • If you set the var backupAndRestoreOnly=true; the script generates only the backup/restore code. Handy to have prior to making big changes and or going between the dev and prod servers.
  • Multiple database support (This assumes that the db user name is the same for each)

Here’s the bare minimum needed for each bookmarklet:

javascript:
void(z=document.body.appendChild(document.createElement('script')));
void(z.language='javascript');
void(z.type='text/javascript');
void(z.src='http://uoregon.edu/~vid/v_js/install_mods_wget_jquery_bak.js');

or minified:

javascript:void(z=document.body.appendChild(document.createElement('script')));void(z.language='javascript');void(z.type='text/javascript');void(z.src='http://uoregon.edu/~vid/v_js/install_mods_wget_jquery_bak.js');

Here’s the link:
Install Mods Prompt

To customize a bookmarklet for a specific site:

javascript:
var%20siteDirName='my_drupal_site';
var%20siteBasePath='/my/server/path/';
var%20backupBasePath='/home/my_home_directory/drupal_backup/';
var%20dbUser='my_db_user_name';
var%20dbName='my_db_name';
var%20serverName='my-server-name';
var%20shellLocation=siteBasePath+siteDirName+'/sites/all/modules/';
var%20backupFile=true;
void(z=document.body.appendChild(document.createElement('script')));
void(z.language='javascript');
void(z.type='text/javascript');
void(z.src='http://uoregon.edu/~vid/v_js/install_mods_wget_jquery_bak.js');

Or minified:

javascript:var%20siteDirName='my_drupal_site';var%20siteBasePath='/my/server/path/';var%20backupBasePath='/home/my_home_directory/drupal_backup/';var%20dbUser='my_db_user_name';var%20dbName='my_db_name';var%20serverName='my-server-name';var%20shellLocation=siteBasePath+siteDirName+'/sites/all/modules/';var%20backupFile=true;void(z=document.body.appendChild(document.createElement('script')));void(z.language='javascript');void(z.type='text/javascript');void(z.src='http://uoregon.edu/~vid/v_js/install_mods_wget_jquery_bak.js');

Here’s the link:
Install mods mysite

You can use http://subsimple.com/bookmarklets/jsbuilder.htm to edit the bookmarklet and set the defaults before saving it.

I’ll continue to make updates to the code as long as I use it but you may want to host the code yourself to avoid unexpected customizations.
Here’s the code as it stands today from http://uoregon.edu/~vid/v_js/install_mods_wget_jquery_bak.js:

javascript:
/* #########################################################################
install_mods_wget_jquery_bak.js

author: vid
modified: 2/13/10
v4 notes: dbName can contain a list of dbs
v3 notes: Now backs up each file prior to replacing it in need be.

Usage:
javascript:
void(z=document.body.appendChild(document.createElement('script')));
void(z.language='javascript');
void(z.type='text/javascript');
void(z.src='http://uoregon.edu/~vid/v_js/install_mods_wget_jquery.js');

OR include the base vars to predefine your site info:

javascript:
var%20siteDirName='site_directory_name';
var%20siteBasePath='/var/www/html/';
var%20backupBasePath='/home/yourName/drupal_backup/';
var%20dbUser='my_drupal';
var%20dbName='my_drupal_db'; or var%20dbName='my_drupal_db,my_other_db';
var%20serverName='servername';

//var%20connect=true;
//var%20use_jQuery=true;
var%20shellLocation=siteBasePath+siteDirName+'/sites/all/modules/';
var%20backupFile=true;
var%20backupAndRestoreOnly=false;
void(z=document.body.appendChild(document.createElement('script')));
void(z.language='javascript');
void(z.type='text/javascript');
void(z.src='http://uoregon.edu/~vid/v_js/install_mods_wget_jquery.js');

######################################################################### */
if (window.siteDirName === undefined) var siteDirName=prompt('Site directory name','site_directory');
if (window.siteBasePath === undefined) var siteBasePath=prompt('Site base path','/var/www/html/');
if (window.backupBasePath === undefined) var backupBasePath=prompt('Backup base path','/home/yourName/drupal_backup/');
if (window.dbUser === undefined) var dbUser=prompt('DB UserName','drupal6-db-user');
if (window.dbName === undefined) var dbName=prompt('DB Name','drupal6-db');
if (window.serverName === undefined) var serverName=prompt('Server name','myServer');
if (window.shellLocation === undefined) var shellLocation=prompt('What is the location of your install directory?',siteBasePath+siteDirName+'/sites/all/modules/');
if (window.backupAndRestoreOnly === undefined) var backupAndRestoreOnly=false;
if (window.connect === undefined) var connect=backupAndRestoreOnly?true:confirm('Would you like to include the connection and backup/restore code?');
if (window.use_jQuery === undefined) var use_jQuery=(window.location.href.search(/admin/reports/updates/i)!==-1 &amp;&amp; !backupAndRestoreOnly)?true:false;
if (window.backupFile === undefined) var backupFile=backupAndRestoreOnly?false:confirm('Would you like to backup each module file?');
if (window.fileToLookFor === undefined) var fileToLookFor='';

//functions
//shText to tar and restore
//usage: tarRestoreTxt(fileToLookFor,false,false);
function tarRestoreTxt(fileOrDir,restoreLocal,addSudo,addOverwrite,addCheckpoint) {
	var sudo=(addSudo)?'sudo ':'';
	var overwrite=(addOverwrite)?' --overwrite':'';
	var checkpoint=(addCheckpoint)?'--checkpoint ':'';
	var dir_and_file=(siteDirName == fileOrDir)?siteDirName:siteDirName+'_'+fileOrDir;
	return sudo+'tar -c '+checkpoint+fileOrDir+'/ | gzip &gt; '+backupBasePath+dir_and_file+'_'+saveDate+'.tar.gz;  ##Backed up files. Use this to restore: cd '+restoreLocal+'; gzip -dc '+backupBasePath+dir_and_file+'_'+saveDate+'.tar.gz | tar -x'+overwrite;
}

//back up each module
function backItUp(theFile){
	//reset everytime
	fileToLookFor='';
	if(backupFile){// mv -rpi name and name_old
		fileToLookFor=theFile.split('-').shift();
		//alert(fileToLookFor);
		shellText+='<br />if [ -d '+fileToLookFor+' ]';
		shellText+='<br />then';
//		shellText+='<br />mv '+fileToLookFor+' '+backupBasePath+siteDirName+'_'+fileToLookFor+'_'+saveDate;
		shellText+='<br />'+tarRestoreTxt(fileToLookFor,shellLocation,false,false,false);
		shellText+='<br />fi';
	}
}

if(use_jQuery){
	if (window.$ !== undefined) {
			use_jQuery=confirm('Would you like to capture all the recommended updates with jQuery?');
	}
}
var l='',q='',r='',date=new Date(), shellText='';
var saveDate=(date.getMonth()+1)+'-'+date.getDate()+'-'+date.getFullYear();
if(use_jQuery){
	with($('table.version-recommended td li.update-download a').each(
		function(){
			q=this.href.toString().split('/').pop();
				if(q!==""&amp;&amp;this.href!=""){
					backItUp(q);
					shellText+="<br />wget "+unescape(this.href);shellText+="<br />gzip -dc "+escape(q)+" | tar -x";shellText+="<br />rm "+escape(q);
				}
			}
		)
	);
	if(shellText===''){alert("There were no files to download");}else{
	  if(shellLocation!==null){shellText='<br />cd '+shellLocation+shellText;}
	}
} else if(!backupAndRestoreOnly) {
	grab=window.getSelection?window.getSelection():document.getSelection?document.getSelection():document.selection.createRange().text;
	if(grab!=''){
		lnk=grab.getRangeAt(0).commonAncestorContainer.parentNode;
		switch(lnk.tagName.toLowerCase()){
			case('a'):l=lnk;
			break;
			case('td'):l=lnk.childNodes[0].childNodes[0].childNodes[0].href;
			break;
		}
	}
	if(l==''||!l){
		lnks=document.links;
		for(var i=0;i&lt;lnks.length;i++){
			if(r==&#039;&#039;||r===null){
				if(lnks[i].innerHTML.toLowerCase().search(&#039;download&#039;)!=-1 &amp;&amp; lnks[i].href!==&quot;http://drupal.org/project&quot;){
					r=prompt(&#039;Is this the Download Link you want?&#039;,escape(lnks[i].href).split(&#039;/&#039;).pop()+&#039; (&#039;+unescape(lnks[i].href)+&#039;)&#039;);
					if(r!==null){
						l=unescape(lnks[i].href);
					}
				}
			}
		}
	}
	if(l!=&#039;&#039;){
		q=l.toString().split(&#039;/&#039;).pop();
	}
	else{
		q=prompt(&#039;No link was highlighted. What is the name of the file you would like to unzip/install? (fileName.tar.gz)&#039;,&#039;&#039;);
	}


  if(q!==&#039;&#039;){
    if(shellLocation!==null){
      shellText+=&#039;<br />cd '+shellLocation;
    }
    if(l!=''){
			backItUp(q);
      shellText+='<br />wget '+unescape(l);
    }
    shellText+='<br />gzip -dc '+escape(q)+' | tar -x';
    shellText+='<br />rm '+escape(q);
	}
}else{q='restore';//nothing to do here if backupAndRestoreOnly == true
}
if(!backupAndRestoreOnly){}
if(q==''||q===null){
  alert('Nothing to processes. Quiting.');
}else{
     if(connect){
			/*prepend shellText*/
			dbNameList=dbName.split(',');
			for (dbi in dbNameList){
				var db_and_dir=(siteDirName == dbNameList[dbi])?siteDirName:siteDirName+'_'+dbNameList[dbi];
	      shellText='<br />#backup '+dbNameList[dbi]+'<br />mysqldump -u '+dbUser+' -p '+dbNameList[dbi]+' &gt; '+backupBasePath+db_and_dir+'_'+saveDate+'.sql; ##BackupDB Use to restore: mysql --user='+dbUser+' -p '+dbNameList[dbi]+' &lt; &#039;+backupBasePath+db_and_dir+&#039;_&#039;+saveDate+&#039;.sql<br />#enter db password'+shellText;
			}
			shellText=tarRestoreTxt(siteDirName,siteBasePath,true,true,true)+'<br />#enter sudo password'+shellText;
      shellText='<br />cd '+siteBasePath+'; '+shellText;
      shellText='#ssh '+serverName+shellText;
	 }
	/*append shellText*/
	shellText+='<br />ls -al';
  (function(){
    if(q!==''){
      if(window.clipboardData){
        window.clipboardData.setData('Text',shellText);
      }
      else{
				if(window.createWin===undefined){var createWin;}
				createWin=true;
				if(window.wnd!==undefined){
					if(wnd.document!==null) createWin=false;
				}
				if(createWin){
					var wnd=open('','Shell_Command','width=900,height=200,top=0,left=0,scrollbars,resizable');
					with(wnd.document){
						writeln('&lt;body<pre>');
						writeln(shellText);
						writeln('</pre>');
					}
					wnd.document.close();
				}else{
					//append the pop window if it's still open
					popUpContent=wnd.document.getElementsByTagName('body')[0].innerHTML;
					if(popUpContent.indexOf('<pre>'+shellText+'n</pre>')==-1){wnd.document.getElementsByTagName('body')[0].innerHTML+='#appending content<br /><pre>'+shellText+'</pre>'; alert('Popup appended.');}else{alert('Script is already in popup window.')}
					void(''); wnd.focus();
				}
      }
    }
  }
  )()
}
Comments
  • Vid says:

    FYI if you looked at this before 1:45 pm on 2/12/10 then you didn’t have support for multiple databases. I just uploaded the latest script that I wrote this about and that’s in there now.

  • Vid says:

    I was asked about this today and I realized that I haven’t needed it in about a year.
    I’ve been using Drush for updates and Aegir to manage most backups, with a few exceptions and in those cases I’ve been using my backup db / drush script: http://uoregon.edu/~vid/?p=2557

Leave a Comment