Archive::Tar uncompress question

Hi Dimitri,

It basically boils down to a case of unexpected usage. The assumption
is that you're creating (or going to create) an archive when you use
Archive::Tar.new.

You are, of course, free to redefine uncompress_archive, but rather than
patching the lib itself, I recommend taking advantage of Ruby's open
classes:

# Somewhere in your code:
module Archive
   class Tar
      def uncompress_archive(program="gunzip")
         @compressed_archive_name = @archive_name unless
@compressed_archive_name
            
         cmd = "#{program} #{@compressed_archive_name}"

         Open3.popen3(cmd){ |prog_in, prog_out, prog_err|
            err = prog_err.gets
            if err
               raise CompressError, err.chomp
            end
            @compressed_archive_name = nil
         }
         self
      end
   end
end

I suppose I could add class methods that would do the sort of thing
you're trying to do. Or, you could add your own class method.

Also note that I'll probably be changing the name to
Archive::Tar::External in the future.

Regards,

Dan

···

-----Original Message-----
From: Dimitri Aivaliotis [mailto:aglarond@gmail.com]
Sent: Thursday, April 06, 2006 1:06 PM
To: ruby-talk ML
Subject: Archive::Tar uncompress question

Hi,

I needed to use Archive::Tar today, and was bit by what I
guess was an unforseen use. I need to simply unpack an
archive, optionally decompressing it first. So, I have code
like this:

    def expand
      t = Archive::Tar.new( @name )
      case @name
      when /\.tar\.bz2/
        t.expand
      when /\.bz2/
        t.uncompress("bunzip2")
      when /\.t(ar\.)?gz/
        t.expand
      when /\.gz/
        t.uncompress("gunzip")
      when /\.zip/
        t.uncompress("unzip")
      else
        raise UnknownArchiveError
      end
    end

which works fine for what I need *if* I redefine
uncompress_archive like so:

<pseudo-patch>
- unless @compressed_archive_name
- raise CompressError, "no compressed file found"
- end
+ unless @compressed_archive_name
+ @compressed_archive_name = @archive_name
+ end
</pseudo-patch>

It seems that @compressed_archive_name can only be set if one
first compresses an archive. I don't need to do that here -
I just need to uncompress an already-existing archive.

Should I be redefining this method or should the package be
changed to the (my) expected behavior? Or have I just
totally missed the usage here? Has anyone else run up against this?

- Dimitri

Hi Dan,

It basically boils down to a case of unexpected usage. The assumption
is that you're creating (or going to create) an archive when you use
Archive::Tar.new.

I actually chose Archive::Tar over Archive::Tar::Minitar because I
needed something quick-and-dirty that could handle all the kinds of
archives in my original post. My application only deals with the
un-packing of these archives - the originals stay where they are, and
my app doesn't create them.

You are, of course, free to redefine uncompress_archive, but rather than
patching the lib itself, I recommend taking advantage of Ruby's open
classes:

# Somewhere in your code:

<snip>

This is actually what I have done. I just presented it in
pseudo-patch form for conciseness, and perhaps to convince you that it
really isn't an error, but could be handled differently. :slight_smile:

I suppose I could add class methods that would do the sort of thing
you're trying to do. Or, you could add your own class method.

A la

module Archive
  class Tar
    attr_accessor :compressed_archive_name
  end
end

?

That still involves redefinition. I try to avoid that with
non-standard-lib libraries. You never know when the name is going to
change. :slight_smile:

Also note that I'll probably be changing the name to
Archive::Tar::External in the future.

Ok, thanks. Interesting naming discussion this started...

- Dimitri

···

On 4/6/06, Berger, Daniel <Daniel.Berger@qwest.com> wrote:

Dimitri Aivaliotis wrote:

Hi Dan,

It basically boils down to a case of unexpected usage. The assumption
is that you're creating (or going to create) an archive when you use
Archive::Tar.new.

I actually chose Archive::Tar over Archive::Tar::Minitar because I
needed something quick-and-dirty that could handle all the kinds of
archives in my original post. My application only deals with the
un-packing of these archives - the originals stay where they are, and
my app doesn't create them.

You are, of course, free to redefine uncompress_archive, but rather than
patching the lib itself, I recommend taking advantage of Ruby's open
classes:

# Somewhere in your code:

<snip>

This is actually what I have done. I just presented it in
pseudo-patch form for conciseness, and perhaps to convince you that it
really isn't an error, but could be handled differently. :slight_smile:

I suppose I could add class methods that would do the sort of thing
you're trying to do. Or, you could add your own class method.

A la

module Archive
  class Tar
    attr_accessor :compressed_archive_name
  end
end

?

That still involves redefinition. I try to avoid that with
non-standard-lib libraries. You never know when the name is going to
change. :slight_smile:

I thought about that, too. I don't see the harm, really. If you want to uncompress an existing archive then it would just be a matter of assigning to that attribute first, then uncompressing.

What makes more sense and/or which would you prefer?

t = Tar::External.new
t.compressed_archive_name = 'somefile.tar.gz'
t.uncompress

# or

Tar::External.uncompress('somefile.tar.gz')

The advantage to the latter is that it's simpler. The drawback is that it wouldn't return an object.

Come to think of it, I should probably manually define compressed_archive_name= like so in order to ensure other instance variables are set properly:

How about this patch:

# Assign a compressed archive name. This autogenerates the archive_name
# based on the extension of the name provided, unless you provide the
# extension yourself. If the extension is '.tgz', then the base of the
# name + '.tar' will be the new archive name.

···

On 4/6/06, Berger, Daniel <Daniel.Berger@qwest.com> wrote:

#
# This should only be used if you have a pre-existing, compressed archive
# that you want to uncompress.
def compressed_archive_name=(name, ext=File.extname(name))
    if ext == ".tgz" || ext == '.TGZ'
       @archive_name = File.basename(name, ext) + '.tar'
    else
       @archive_name = File.basename(name, ext)
    end
    @compressed_archive_name = name
end

Thoughts?

Dan

PS - Perhaps we should continue this over on the Shards project page under "Open Discussion". See http://www.rubyforge.org/projects/shards\.

What makes more sense and/or which would you prefer?

t = Tar::External.new
t.compressed_archive_name = 'somefile.tar.gz'
t.uncompress

# or

Tar::External.uncompress('somefile.tar.gz')

The advantage to the latter is that it's simpler. The drawback is that it
wouldn't return an object.

I prefer the latter. Would you really need an object returned if
you're just uncompressing an archive?

Come to think of it, I should probably manually define compressed_archive_name=
like so in order to ensure other instance variables are set properly:

How about this patch:

<snip>

Thoughts?

Looks good. I would still change the "unless" clause in the
uncompress_archive method, in addition to this patch. Then both
methods of uncompressing could be supported.

PS - Perhaps we should continue this over on the Shards project page under
"Open Discussion". See http://www.rubyforge.org/projects/shards\.

I'm happy with where this thread has ended up. If you feel more
discussion is necessary, let me know, and I'll follow you over there.

- Dimitri

···

On 4/6/06, Daniel Berger <Daniel.Berger@qwest.com> wrote:

Dimitri Aivaliotis wrote:

<snip>

Looks good. I would still change the "unless" clause in the
uncompress_archive method, in addition to this patch. Then both
methods of uncompressing could be supported.

PS - Perhaps we should continue this over on the Shards project page under
"Open Discussion". See http://www.rubyforge.org/projects/shards\.

I'm happy with where this thread has ended up. If you feel more
discussion is necessary, let me know, and I'll follow you over there.

- Dimitri

Ok, cool. I've renamed everything and put a new release out.

Thanks for the feedback.

Dan

···

On 4/6/06, Daniel Berger <Daniel.Berger@qwest.com> wrote:

Great! Thanks, Dan. I'll put those new methods to work on Monday.

- Dimitri

···

On 4/7/06, Daniel Berger <Daniel.Berger@qwest.com> wrote:

Ok, cool. I've renamed everything and put a new release out.