Two Functions for Migrating S Objects

B. Narasimhan
Department of Statistics
Stanford University
Stanford, CA 94305

Version of 1997/05/20

Table of Contents

Introduction

[*]

One of the chores of migrating from one platform to another is that S objects need to be migrated too. We provide two functions Dump.All and Undump.All to aid in this process. These functions are meant to be used as follows.

Suppose user Joe (userid joe) wishes to move objects from platform A to platform B. As a first step, Joe transfers all his files from A to B using some program like tar, preserving his directory structure. On platform A Joe invokes S from his home directory and executes the command

> Dump.All("/var/tmp")
The argument to the function is a directory which is assumed to have enough space to hold all the dumped files. If everything goes well, Joe will have a gzip'ed tar ball called joe.tar.gz in the directory /var/tmp. Joe can now ftp the file over to platform B in binary mode, say, to a directory /tmp, invoke S from his home directory there and type
> Undump.All("/tmp")
to restore all his objects.

Some assumptions.

Copyright

[*]

We begin with our usual copyright.

<Copyright>= (U->)
#
# $Revision: 1.1 $
#
# Copyright (C) 1996, B. Narasimhan (naras@stat.stanford.edu)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

The functions

[*]

The two functions are, of course, Dump.All and UnDump.All.

<*>=
<Copyright>
<Dump.All function>
<Undump.All function>

The Dump.All function

[*]

The function is quite easy to describe.

<Dump.All function>= (<-U)
Dump.All <- function(dest.dir="~", find.cmd="find") 
{
  <Set up dump names and map name>
  data.dirs <- <List all data directories>
  for (i in seq(along = data.dirs))
    {
      <Dump directory i>
      <Update map file>
    }
  <Make tar.gz ball>
  <Clean up>
  <Print cautionary message>
}
Defines data.dirs, dest.dir, Dump.All (links are to index).

I will be using all.dump.names to build up a string of all the dump filenames to be fed to the tar program. The correspondence between the dump files and the directories will be stored in the map file.

<Set up dump names and map name>= (<-U)
  whoami <- unix("whoami")
  all.dump.names <-  ""
  dump.map.name<- paste(whoami, "map", sep=".")
  dump.map.pathname <- paste(dest.dir, dump.map.name, sep="/")
Defines all.dump.names, dump.map.name, dump.map.pathname, whoami (links are to index).

The list of data directories is best found by the find program.

<List all data directories>= (<-U)
unix(paste(find.cmd, ". -name '.Data*' -type d -follow -print"))

On to dumping S objects. Let us tell the user what is going on.

<Dump directory i>= (<-U) [D->]
print(paste("Processing", data.dirs[i]))

Since many people could be doing this at the same time, we want to keep the dump file names unique. So we'll use joe.Dump.1, joe.Dump.2 etc., for the dump file names. Also we dump the objects to the file in the specified destination directory.

<Dump directory i>+= (<-U) [<-D->]
dump.name <- paste(whoami, "Dump", i, sep=".")
attach(data.dirs[i])
data.dump(objects(2), file = paste(dest.dir, dump.name, sep="/"))
detach(data.dirs[i])
Defines dump.name (links are to index).

After a directory is done, we inform the user and update our string of dump names. We also add an entry to the map file.

<Dump directory i>+= (<-U) [<-D]
print(paste("Wrote", paste(dest.dir, dump.name, sep="/")))
all.dump.names <- paste(all.dump.names, dump.name)

The map file needs to be updated to reflect the correspondence between directories and dumps.

<Update map file>= (<-U)
unix(paste("echo", dump.name, data.dirs[i], ">>", dump.map.pathname))

Now we are ready to make our tar ball. With GNU tar, the following could be done in one step since GNU tar can compress and decompress. We'll do it the traditional way.

<Make tar.gz ball>= (<-U)
tar.name <- paste(whoami, "tar", sep=".")
unix(paste("cd", dest.dir, "; tar -cvf", tar.name, all.dump.names, 
     dump.map.name))
unix(paste("cd", dest.dir, "; gzip", tar.name))
Defines tar.name (links are to index).

We can now remove all the dump files and the map file.

<Clean up>= (<-U)
unix(paste("cd", dest.dir, "; rm", all.dump.names, dump.map.name))

The cautionary message.

<Print cautionary message>= (<-U)
print("Warning: Before relying completely on the dumps")
print("  make sure that ")
print("  1) no errors occured AT ALL")
print("  2) you test the objects on the other system")
print("    before deleting the .Data directories on the current system.")
print("Dumping finished. You can now ftp the file ")
print(paste("  ", tar.name, ".gz", sep=""))
print("to the other machine. Be sure to use a binary transfer.")
return("")

The Undump.All function

[*]

We just have to undo what we did. This is far easier.

<Undump.All function>= (<-U)
Undump.All <- function(src.dir) 
{
  <Find and explode tar.gz ball>
  <Find map name>
  <Read in map file>
  for (i in seq(along = map$dump.names))
    {
      <Prepare directory of interest>
      <Attach the directory at head of list>
      <Restore dump>
      <Detach directory>
      print(paste("Restored objects in", map$dump.dirnames[i]))
    }
  return("Undump.All finished.")
}
Defines src.dir, Undump.All (links are to index).

To explode the tar ball, we run a unix command.

<Find and explode tar.gz ball>= (<-U)
whoami <- unix("whoami")
tar.gz.name <- paste(whoami,"tar.gz", sep=".")
unix(paste("cd", src.dir, "; gunzip -c", tar.gz.name, "| tar -xf -"))
Defines tar.gz.name (links are to index).

The map name is userid.map.

<Find map name>= (<-U)
map.name <- paste(whoami, "map", sep=".")
Defines map.name (links are to index).

The map file contains two columns, a dump file name and the directory of which it is the dump.

<Read in map file>= (<-U)
map <- scan(paste(src.dir, map.name, sep="/"),
         what = list(dump.names="", dump.dirnames=""))
Defines map (links are to index).

Since we have assumed the user transferred all his files first, the .Data directories, though unusable, will exist. Time to get rid of objects in that directory.

<Prepare directory of interest>= (<-U)
unix(paste("cd", map$dump.dirnames[i], "; rm -rf *"))

The rest of the code is self-explanatory.

<Attach the directory at head of list>= (<-U)
attach(map$dump.dirnames[i])
detach(".Data")

<Restore dump>= (<-U)
data.restore(paste(src.dir, map$dump.names[i], sep="/"))

<Detach directory>= (<-U)
attach(".Data")
detach(map$dump.dirnames[i])

Indices

[*]

Code Chunks

[*] This index is generated automatically. The numeral is that of the first definition of the chunk.

Index of Identifiers

[*] Here is a list of the identifiers used, and where they appear. Underlined entries indicate the place of definition. This index is generated automatically.