Module: RUtilAnts::Misc

Defined in:
lib/rUtilAnts/Misc.rb

Constant Summary collapse

FILEMUTEX_NO_LOCK =

Constants used for file_mutex There was no lock on the mutex

0
FILEMUTEX_ZOMBIE_LOCK =

There was a lock on the mutex, but former process did not exist anymore

1
FILEMUTEX_LOCK_TAKEN =

The lock is taken by a running process

2
FILEMUTEX_INVALID_LOCK =

The lock file is invalid

3

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.install_misc_on_objectObject

Set these methods into the Object namespace



6
7
8
# File 'lib/rUtilAnts/Misc.rb', line 6

def self.install_misc_on_object
  Object.module_eval('include RUtilAnts::Misc')
end

Instance Method Details

#cached_var(&iCode) ⇒ Object

Cache the access to a given code result, based on the caller ID This can be used to cache variables computation (ex. lVar = cached_var{ lengthyFctToComputeVar } )

Parameters
  • *&iCode* (CodeBlock): The code called to compute the result

    • Return
      • Object: The computed result

Return
  • Object: The result of the code



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/rUtilAnts/Misc.rb', line 19

def cached_var(&iCode)
  if (defined?(@RUtilAnts_Misc_CachedVars) == nil)
    @RUtilAnts_Misc_CachedVars = {}
  end
  # Compute the hash of this code
  lHash = caller[0].hash
  if (@RUtilAnts_Misc_CachedVars[lHash] == nil)
    @RUtilAnts_Misc_CachedVars[lHash] = iCode.call
  end

  return @RUtilAnts_Misc_CachedVars[lHash]
end

#change_dir(iDir) ⇒ Object

Execute a code block after having changed current directory. Ensure the directory will be changed back at the end of the block, even if exceptions are thrown.

Parameters
  • iDir (String): The directory to change into

  • CodeBlock: Code called once the current directory has been changed



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/rUtilAnts/Misc.rb', line 153

def change_dir(iDir)
  lOldDir = Dir.getwd
  Dir.chdir(iDir)
  begin
    yield
  rescue Exception
    Dir.chdir(lOldDir)
    raise
  end
  Dir.chdir(lOldDir)
end

#extract_zip_file(iZipFileName, iDirName) ⇒ Object

Extract a Zip archive in a given system dependent lib sub-directory

Parameters
  • iZipFileName (String): The zip file name to extract content from

  • iDirName (String): The name of the directory to store the zip to

Return
  • Exception: Error, or nil in case of success



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/rUtilAnts/Misc.rb', line 53

def extract_zip_file(iZipFileName, iDirName)
  rError = nil

  # Use RDI if possible to ensure the dependencies on zlib.dll and rubyzip
  if (defined?(RDI) != nil)
    lRDIInstaller = RDI::Installer.get_main_instance
    if (lRDIInstaller != nil)
      # First, test that the DLL exists.
      # If it does not exist, we can't install it, because ZLib.dll is downloadable only in ZIP format (kind of stupid ;-) )
      lDLLDep = nil
      case os
      when OS_WINDOWS
        lDLLDep = RDI::Model::DependencyDescription.new('ZLib DLL').add_description( {
          :Testers => [
            {
              :Type => 'DynamicLibraries',
              :Content => [ 'zlib.dll' ]
            }
          ],
          # We can't install this one
          :Installers => []
        } )
      else
        log_bug "Sorry, installing ZLib on your platform #{os} is not yet supported."
      end
      if ((lDLLDep != nil) and
          (!lRDIInstaller.test_dependency(lDLLDep)))
        # Try adding the default local location for libraries
        lRDIInstaller.ensure_location_in_context('LibraryPath', lRDIInstaller.get_default_install_location('Download', RDI::DEST_LOCAL))
        # Try again
        if (!lRDIInstaller.test_dependency(lDLLDep))
          log_err "zlib.dll is not installed in your system.\nUnfortunately RDI can't help because the only way to install it is to download it through a ZIP file.\nPlease install it manually from http://zlib.net (you can do it now and click OK once it is installed)."
        end
      end
      # Then, ensure the gem dependency
      rError, _, lIgnored, lUnresolved = lRDIInstaller.ensure_dependencies(
        [
          RDI::Model::DependencyDescription.new('RubyZip').add_description( {
            :Testers => [
              {
                :Type => 'RubyRequires',
                :Content => [ 'zip/zipfilesystem' ]
              }
            ],
            :Installers => [
              {
                :Type => 'Gem',
                :Content => 'rubyzip',
                :ContextModifiers => [
                  {
                    :Type => 'GemPath',
                    :Content => '%INSTALLDIR%'
                  }
                ]
              }
            ]
          } )
        ]
      )
      if (!lIgnored.empty?)
        rError = RuntimeError.new("Unable to install RubyZip without its dependencies (#{lIgnored.size} ignored dependencies).")
      elsif (!lUnresolved.empty?)
        rError = RuntimeError.new("Unable to install RubyZip without its dependencies (#{lUnresolved.size} unresolved dependencies):\n#{rError}")
      end
    end
  end
  if (rError == nil)
    # Extract content of iFileName to iDirName
    begin
      # We don't put this require in the global scope as it needs first a DLL to be loaded by plugins
      require 'zip/zipfilesystem'
      Zip::ZipInputStream::open(iZipFileName) do |iZipFile|
        while (lEntry = iZipFile.get_next_entry)
          lDestFileName = "#{iDirName}/#{lEntry.name}"
          if (lEntry.directory?)
            FileUtils::mkdir_p(lDestFileName)
          else
            FileUtils::mkdir_p(File.dirname(lDestFileName))
            # If the file already exist, first delete it to replace it with ours
            if (File.exists?(lDestFileName))
              File.unlink(lDestFileName)
            end
            lEntry.extract(lDestFileName)
          end
        end
      end
    rescue Exception
      rError = $!
    end
  end

  return rError
end

#file_mutex(iProcessID) ⇒ Object

Execute a code block protected by a file mutex

Parameters
  • iProcessID (String): Process ID to be used to identify the mutex

  • CodeBlock: The code called if the mutex is taken

Return
  • Integer: Error code



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/rUtilAnts/Misc.rb', line 181

def file_mutex(iProcessID)
  rResult = FILEMUTEX_NO_LOCK

  # Prevent concurrent execution
  require 'tmpdir'
  lLockFile = "#{Dir.tmpdir}/FileMutex_#{iProcessID}.lock"
  if (File.exists?(lLockFile))
    log_err "Another instance of process #{iProcessID} is already running. Delete file #{lLockFile} if it is not."
    begin
      lDetails = nil
      File.open(lLockFile, 'r') do |iFile|
        lDetails = eval(iFile.read)
      end
      log_err "Details of the running instance: #{lDetails.inspect}"
      # If the process does not exist anymore, remove the lock file
      # TODO: Adapt this to non Unix systems
      if (File.exists?("/proc/#{lDetails[:PID]}"))
        rResult = FILEMUTEX_LOCK_TAKEN
      else
        log_err "Process #{lDetails[:PID]} does not exist anymore. Removing lock file."
        File.unlink(lLockFile)
        rResult = FILEMUTEX_ZOMBIE_LOCK
      end
    rescue Exception
      log_err "Invalid lock file #{lLockFile}: #{$!}."
      rResult = FILEMUTEX_INVALID_LOCK
    end
  end
  if ((rResult == FILEMUTEX_NO_LOCK) or
      (rResult == FILEMUTEX_ZOMBIE_LOCK))
    # Create the lock for our process
    File.open(lLockFile, 'w') do |oFile|
      oFile << "
        {
          :ExecutionTime => '#{DateTime.now.strftime('%Y-%m-%d %H:%M:%S')}',
          :PID => '#{Process.pid}'
        }
      "
    end
    begin
      yield
      File.unlink(lLockFile)
    rescue Exception
      begin
        File.unlink(lLockFile)
      rescue Exception
        log_err "Exception while deleting lock file #{lLockFile}: #{$!}"
      end
      raise
    end
  end

  return rResult
end

#get_valid_file_name(iFileName) ⇒ Object

Get a valid file name, taking into account platform specifically prohibited characters in file names.

Parameters
  • iFileName (String): The original file name wanted

Return
  • String: The correct file name



38
39
40
41
42
43
44
# File 'lib/rUtilAnts/Misc.rb', line 38

def get_valid_file_name(iFileName)
  if (defined?(prohibited_file_names_chars) != nil)
    return iFileName.gsub(/[#{Regexp.escape(prohibited_file_names_chars)}]/, '_')
  else
    return iFileName
  end
end

#replace_vars(iStr, iVars) ⇒ Object

Replace variables of the form %VariableName from a string. Take values from a hash having :VariableName => ‘VariableValue’. Works also recursively if a variable value contains again %OtherVariableName. Does not check if variables really exist (will replace any unknown variable with ”).

Parameters
  • iStr (String): The string to replace from

  • iVars (map<Symbol,String>): The variables

Return
  • String: The string replaced



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/rUtilAnts/Misc.rb', line 246

def replace_vars(iStr, iVars)
  rStr = iStr

  lFinished = false
  while (!lFinished)
    lMatch = rStr.match(/^(.*[^%])%\{([^\}]+)\}(.*)$/)
    if (lMatch == nil)
      # Try with %{ at the beginning of the string
      lMatch = rStr.match(/^%\{([^\}]+)\}(.*)$/)
      if (lMatch == nil)
        # No more occurrences
        lFinished = true
      else
        rStr = "#{iVars[lMatch[1].to_sym]}#{lMatch[2]}"
      end
    else
      rStr = "#{lMatch[1]}#{iVars[lMatch[2].to_sym]}#{lMatch[3]}"
    end
  end

  return rStr
end