Class: Omnizip::Formats::Rar::ExternalWriter

Inherits:
Object
  • Object
show all
Defined in:
lib/omnizip/formats/rar/external_writer.rb

Overview

External RAR writer using licensed WinRAR installation

This class provides RAR archive creation by wrapping the user's licensed WinRAR command-line tool. It does NOT implement RAR compression internally due to proprietary licensing restrictions.

Examples:

Create a RAR archive

writer = ExternalWriter.new('archive.rar')
writer.add_file('document.pdf')
writer.add_directory('photos/')
writer.write

Create with options

writer = ExternalWriter.new('archive.rar',
  compression: :best,
  solid: true,
  recovery: 5
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output_path, options = {}) ⇒ ExternalWriter

Initialize RAR writer

Parameters:

  • output_path (String)

    Output RAR file path

  • options (Hash) (defaults to: {})

    Compression options

Options Hash (options):

  • :compression (Symbol)

    Compression level (:store, :fastest, :fast, :normal, :good, :best)

  • :solid (Boolean)

    Create solid archive

  • :recovery (Integer)

    Recovery record percentage (0-10)

  • :encrypt_headers (Boolean)

    Encrypt file names

  • :password (String)

    Archive password

  • :volume_size (Integer)

    Split into volumes (bytes)

  • :test_after_create (Boolean)

    Test archive after creation

  • :license_confirmed (Boolean)

    Skip license confirmation



85
86
87
88
89
90
91
92
93
# File 'lib/omnizip/formats/rar/external_writer.rb', line 85

def initialize(output_path, options = {})
  @output_path = output_path
  @options = default_options.merge(options)
  @files = []
  @directories = []

  validate_availability!
  validate_license! unless @options[:license_confirmed]
end

Instance Attribute Details

#filesArray<String> (readonly)

Returns Files to add.

Returns:

  • (Array<String>)

    Files to add



35
36
37
# File 'lib/omnizip/formats/rar/external_writer.rb', line 35

def files
  @files
end

#optionsHash (readonly)

Returns Compression options.

Returns:

  • (Hash)

    Compression options



32
33
34
# File 'lib/omnizip/formats/rar/external_writer.rb', line 32

def options
  @options
end

#output_pathString (readonly)

Returns Output archive path.

Returns:

  • (String)

    Output archive path



29
30
31
# File 'lib/omnizip/formats/rar/external_writer.rb', line 29

def output_path
  @output_path
end

Class Method Details

.available?Boolean

Check if RAR creation is available

Returns:

  • (Boolean)

    true if WinRAR executable found



40
41
42
# File 'lib/omnizip/formats/rar/external_writer.rb', line 40

def self.available?
  !find_rar_executable.nil?
end

.find_rar_executableString?

Find RAR executable on system

Returns:

  • (String, nil)

    Path to executable or nil



64
65
66
67
68
69
70
# File 'lib/omnizip/formats/rar/external_writer.rb', line 64

def self.find_rar_executable
  if RUBY_PLATFORM.match?(/win32|mingw/)
    find_windows_rar
  else
    find_unix_rar
  end
end

.find_unix_rarString?

Find RAR on Unix systems

Returns:

  • (String, nil)

    Path or nil



290
291
292
# File 'lib/omnizip/formats/rar/external_writer.rb', line 290

def self.find_unix_rar
  which("rar")
end

.find_windows_rarString?

Find WinRAR on Windows

Returns:

  • (String, nil)

    Path or nil



273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/omnizip/formats/rar/external_writer.rb', line 273

def self.find_windows_rar
  # Check common installation paths
  paths = [
    "C:\\Program Files\\WinRAR\\Rar.exe",
    "C:\\Program Files (x86)\\WinRAR\\Rar.exe",
  ]

  # Check PATH
  path_rar = which("rar.exe") || which("Rar.exe")
  paths.unshift(path_rar) if path_rar

  paths.find { |path| File.exist?(path) }
end

.infoHash

Get RAR executable information

Returns:

  • (Hash)

    Executable path and version



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/omnizip/formats/rar/external_writer.rb', line 47

def self.info
  exe = find_rar_executable
  return { available: false } unless exe

  version_output, = Open3.capture2e(exe)
  version = version_output.match(/RAR\s+([\d.]+)/i)&.[](1) || "unknown"

  {
    available: true,
    executable: exe,
    version: version,
  }
end

.which(cmd) ⇒ String?

Find executable in PATH

Parameters:

  • cmd (String)

    Command name

Returns:

  • (String, nil)

    Path or nil



298
299
300
301
302
303
304
305
306
307
# File 'lib/omnizip/formats/rar/external_writer.rb', line 298

def self.which(cmd)
  exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
  ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
    exts.each do |ext|
      exe = File.join(path, "#{cmd}#{ext}")
      return exe if File.executable?(exe) && !File.directory?(exe)
    end
  end
  nil
end

Instance Method Details

#add_directory(dir_path, recursive: true, archive_path: nil) ⇒ Object

Add directory to archive

Parameters:

  • dir_path (String)

    Path to directory

  • recursive (Boolean) (defaults to: true)

    Include subdirectories

  • archive_path (String, nil) (defaults to: nil)

    Path within archive

Raises:

  • (ArgumentError)

    if directory does not exist



116
117
118
119
120
121
122
123
124
125
# File 'lib/omnizip/formats/rar/external_writer.rb', line 116

def add_directory(dir_path, recursive: true, archive_path: nil)
  raise ArgumentError, "Directory not found: #{dir_path}" unless
    Dir.exist?(dir_path)

  @directories << {
    source: File.expand_path(dir_path),
    recursive: recursive,
    archive_path: archive_path,
  }
end

#add_file(file_path, archive_path = nil) ⇒ Object

Add file to archive

Parameters:

  • file_path (String)

    Path to file

  • archive_path (String, nil) (defaults to: nil)

    Path within archive

Raises:

  • (ArgumentError)

    if file does not exist



100
101
102
103
104
105
106
107
108
# File 'lib/omnizip/formats/rar/external_writer.rb', line 100

def add_file(file_path, archive_path = nil)
  raise ArgumentError, "File not found: #{file_path}" unless
    File.exist?(file_path)

  @files << {
    source: File.expand_path(file_path),
    archive_path: archive_path,
  }
end

#writeObject

Create RAR archive

Raises:



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/omnizip/formats/rar/external_writer.rb', line 131

def write
  raise RarNotAvailableError unless self.class.available?

  # Build command
  cmd = build_command

  # Execute RAR
  stdout, stderr, status = Open3.capture3(*cmd)

  unless status.success?
    raise "RAR creation failed: #{stderr}\n#{stdout}"
  end

  # Test archive if requested
  test_archive if @options[:test_after_create]

  @output_path
end