Class: Distem::Lib::FileManager

Inherits:
Object
  • Object
show all
Defined in:
lib/distem/distemlib/filemanager.rb

Overview

Class that allow to manage files and archives (extracting, downloading, …)

Constant Summary

PATH_DEFAULT_DOWNLOAD =

The directory used to store downloaded files

'/tmp/distem/downloads/'
PATH_DEFAULT_CACHE =

The directory used to store archive extraction cache

'/tmp/distem/extractcache/'
PATH_DEFAULT_COMPRESS =

The directory used to store compressed files

'/tmp/distem/files/'
BIN_TAR =

:nodoc:

'tar'
@@lock =

:nodoc:

Mutex.new
@@hashcache =
{}
@@archivecache =

:nodoc:

[]
@@cowcache =

:nodoc:

[]

Class Method Summary (collapse)

Class Method Details

+ (Object) cache_archive(archivefile, filehash, cow)

Cache an archive fine in the cache. Only one file can be cached at the same time (mutex).

Attributes

  • archivefile The path to the archive file (String)

  • filehash The hash of the archive file (String)

Returns

String value describing the path to the directory (on the local machine) the file was cached to



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/distem/distemlib/filemanager.rb', line 124

def self.cache_archive(archivefile,filehash,cow)
  Lib::Shell.run("mkdir -p #{PATH_DEFAULT_CACHE}") if !File.exist?(PATH_DEFAULT_CACHE)
  cachedir = File.join(PATH_DEFAULT_CACHE,filehash)
  newcache = false

  unless @@archivecache.include?(filehash)
    @@archivecache << filehash
    if File.exist?(cachedir)
      Lib::Shell.run("rm -R #{cachedir}")
    end
    if cow
      Lib::Shell.run("btrfs subvolume create #{cachedir}")
      @@cowcache << cachedir
    end
    extract!(archivefile,cachedir)
    newcache = true
  end
  return cachedir,newcache
end

+ (Object) clean_cache



145
146
147
148
149
150
151
# File 'lib/distem/distemlib/filemanager.rb', line 145

def self.clean_cache
  @@lock.synchronize {
    @@cowcache.each { |path|
      Lib::Shell.run("btrfs subvolume delete #{path}")
    }
  }
end

+ (Object) compress(filepath)

Compress a file using TGZ archive format.

Attributes

  • filepath The path to the file (String)

Returns

String value describing the path to the directory (on the local machine) the generated archive file is store to



159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/distem/distemlib/filemanager.rb', line 159

def self.compress(filepath)
  raise Lib::ResourceNotFoundError, filepath \
    unless File.exist?(filepath)
  unless File.exist?(PATH_DEFAULT_COMPRESS)
    Lib::Shell.run("mkdir -p #{PATH_DEFAULT_COMPRESS}")
  end

  basename = File.basename(filepath)
  respath = "#{File.join(PATH_DEFAULT_COMPRESS,basename)}.tar.gz"
  Lib::Shell.run("#{BIN_TAR} czf #{respath} -C #{filepath} .")

  return respath
end

+ (Object) download(uri_str, dir = PATH_DEFAULT_DOWNLOAD)

Download a file using a specific protocol and store it on the local machine

Attributes

  • uri_str The URI of the file to download

  • dir The directory to save the file to

Returns

String value describing the path to the downloaded file on the local machine

Exceptions

  • InvalidParameterError if the specified URI is not valid

  • ResourceNotFoundError if can't reach the specified file

  • NotImplementedError if the protocol specified in the URI is not supported (atm only file:// is supported)



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/distem/distemlib/filemanager.rb', line 37

def self.download(uri_str,dir=PATH_DEFAULT_DOWNLOAD)
  begin
    uri = URI.parse(CGI.unescape(uri_str))
  rescue URI::InvalidURIError
    raise Lib::InvalidParameterError, uri_str
  end

  ret = ""

  case uri.scheme
    when "file"
      ret = uri.path
      raise Lib::ResourceNotFoundError, ret unless File.exist?(ret)
    else
      raise Lib::NotImplementedError, uri.scheme
  end

  return ret
end

+ (Object) extract(archivefile, targetdir = "", override = true, cow = false)

Extract an archive file in the specified directory using a cache. The cache: if unarchiving two times the same archive, the unarchive cache is used to only have to copy files from the cache (no need to unarchive another time).

Attributes

  • archivefile The path to the archive file (String)

  • targetdir The directory to unarchive the file to

Returns

String value describing the path to the directory (on the local machine) the file was unarchived to

Exceptions

  • ResourceNotFoundError if can't reach the specified archive file

  • NotImplementedError if the archive file format is not supported (available: tar, gzip, bzip, zip, (tgz,…))



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/distem/distemlib/filemanager.rb', line 67

def self.extract(archivefile,targetdir="",override=true,cow=false)
  raise Lib::ResourceNotFoundError, archivefile unless File.exist?(archivefile)

  if targetdir.empty?
    targetdir = File.dirname(archivefile)
  end

  filehash = file_hash(archivefile)

  @@lock.synchronize {
    cachedir,new = cache_archive(archivefile,filehash,cow)
    exists = File.exist?(targetdir)
    if !exists or override or new
      Lib::Shell.run("rm -Rf #{targetdir}") if exists
      if cow
        Lib::Shell.run("btrfs subvolume snapshot #{cachedir} #{targetdir}")
      else
        Lib::Shell.run("mkdir -p #{targetdir}")
        Lib::Shell.run("cp -af #{File.join(cachedir,'*')} #{targetdir}")
      end
    end
  }
  return targetdir
end

+ (Object) extract!(archivefile, target_dir)

Extract an archive file in the specified directory without using the cache and the MAX_SIMULTANEOUS_EXTRACT limitation.

Attributes

  • archivefile The path to the archive file (String)

  • targetdir The directory to unarchive the file to

Returns

String value describing the path to the directory (on the local machine) the file was unarchived to

Exceptions

  • ResourceNotFoundError if can't reach the specified archive file

  • NotImplementedError if the archive file format is not supported (available: tar, gzip, bzip, zip, (tgz,…))



102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/distem/distemlib/filemanager.rb', line 102

def self.extract!(archivefile,target_dir)
  raise Lib::ResourceNotFoundError, archivefile \
    unless File.exist?(archivefile)

  unless File.exist?(target_dir)
    Lib::Shell.run("mkdir -p #{target_dir}")
  end

  basename = File.basename(archivefile)
  link = File.join(target_dir, basename)
  Lib::Shell.run("ln -sf #{archivefile} #{link}")
  Lib::Shell.run("(cd #{target_dir} && #{BIN_TAR} xf #{basename})")
  Lib::Shell.run("rm #{link}")
end

+ (Object) file_hash(filename)

Get a “unique” file identifier from a specific file

Attributes

  • filename The path to the file (String)

Returns

String value describing the “unique” hash



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/distem/distemlib/filemanager.rb', line 179

def self.file_hash(filename)
  ret = nil
  @@lock.synchronize do
    unless @@hashcache[filename] and @@hashcache[filename][:mtime] == (mtime= File.mtime(filename))
      unless @@hashcache[filename]
        mtime = File.mtime(filename) unless mtime
        sha256 = `sha256sum #{filename}|cut -f1 -d' '`.chomp
        # if sha256sum is not functional, we use the slower Ruby version
        if (sha256 == '')
          sha256 = Digest::SHA256.file(filename).hexdigest
        end
        @@hashcache[filename] = {
          :mtime => mtime,
          :hash => "#{File.basename(filename)}-#{mtime.to_i.to_s}-#{File.stat(filename).size.to_s}-#{sha256}"
        }
      end
    end
    ret = @@hashcache[filename][:hash]
  end

  return ret
end