tpkg 1.23.3 → 1.25.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ spec = Gem::Specification.new do |s|
5
5
  s.add_dependency('facter')
6
6
  s.add_dependency('net-ssh')
7
7
  s.add_dependency('ddao-kwalify')
8
- s.version = '1.23.3'
8
+ s.version = '1.25.1'
9
9
  s.authors = ['Darren Dao', 'Jason Heiss']
10
10
  s.email = 'tpkg-users@lists.sourceforge.net'
11
11
  s.homepage = 'http://tpkg.sourceforge.net'
@@ -35,6 +35,7 @@ end
35
35
  @gemcmd = DEFAULT_GEM_COMMAND
36
36
  @rubygemspath = nil
37
37
  @extrapkgname = nil
38
+ @verbose = false
38
39
 
39
40
  opts = OptionParser.new
40
41
  opts.banner = 'Usage: gem2tpkg [options] GEMNAME1 GEMNAME2 ...'
@@ -85,6 +86,9 @@ end
85
86
  opts.on('--extra-name', '=EXTRANAME', 'Extra string to add to package name') do |opt|
86
87
  @extrapkgname = opt
87
88
  end
89
+ opts.on('--verbose', 'Provides more info on what is being executed') do |opt|
90
+ @verbose = opt
91
+ end
88
92
  opts.on_tail("-h", "--help", "Show this message") do
89
93
  puts opts
90
94
  exit
@@ -99,7 +103,9 @@ leftover = opts.parse(ARGV)
99
103
  @geminstallpath = nil
100
104
  @gembinpath = nil
101
105
  @rubypath = nil
102
- IO.popen("#{@gemcmd} environment") do |pipe|
106
+ cmd = "#{@gemcmd} environment"
107
+ puts "Executing: #{cmd}" if @verbose
108
+ IO.popen(cmd) do |pipe|
103
109
  pipe.each_line do |line|
104
110
  if line =~ /INSTALLATION DIRECTORY:\s+(\S+)/
105
111
  @geminstallpath = $1
@@ -180,6 +186,7 @@ if !@buildopts.empty?
180
186
  geminst.concat(@buildopts)
181
187
  end
182
188
 
189
+ puts "Executing: #{geminst.join(" ")}" if @verbose
183
190
  r = system(*geminst)
184
191
  if !r
185
192
  abort('gem install failed')
@@ -240,7 +247,9 @@ def package(gem)
240
247
  # We want to exactly match the gem in question. Turns out that if you
241
248
  # pass something that looks like a regex then gem dependency will use
242
249
  # that instead. See rubygems/commands/dependency_command.rb
243
- IO.popen("#{@gemcmd} dependency /^#{Regexp.escape(gem)}$/") do |pipe|
250
+ cmd = "#{@gemcmd} dependency /^#{Regexp.escape(gem)}$/"
251
+ puts "Executing: #{cmd}" if @verbose
252
+ IO.popen(cmd) do |pipe|
244
253
  pipe.each_line do |line|
245
254
  next if line =~ /^Gem / # Skip header line
246
255
  next if line =~ /^\s*$/ # Skip blank lines
data/bin/tpkg CHANGED
@@ -31,7 +31,7 @@ require 'tpkg'
31
31
  @tpkg_options = {} # options for instantiating Tpkg object
32
32
  @init_options = {} # options for how to run init scripts
33
33
  @other_options = {}
34
- @compress = nil
34
+ @compress = "gzip"
35
35
 
36
36
 
37
37
  def rerun_with_sudo_if_necessary
@@ -214,12 +214,19 @@ opts.on('--qX', '=FILENAME', 'Display tpkg.xml or tpkg.yml of the given package'
214
214
  @action = :query_tpkg_metadata
215
215
  @action_value = opt
216
216
  end
217
+ opts.on('--history', 'Display package installation history') do |opt|
218
+ @action = :query_history
219
+ end
217
220
  opts.on('--qenv', "Display machine's information") do |opt|
218
221
  @action = :query_env
219
222
  end
220
223
  opts.on('--source', '=NAME', 'Sources where packages are located', Array) do |opt|
221
224
  @tpkg_options["sources"] = opt
222
225
  end
226
+ opts.on('--download', '=PACKAGES', 'Download one or more packages', Array) do |opt|
227
+ @action = :download
228
+ @action_value = opt
229
+ end
223
230
  opts.on('-n', '--no-prompt', 'No confirmation prompts') do |opt|
224
231
  @prompt = opt
225
232
  Tpkg::set_prompt(@prompt)
@@ -252,7 +259,11 @@ opts.on('--deploy-as', '=USERNAME', 'What username to use for deploying to remot
252
259
  @deploy_params = @deploy_params - ['--deploy-as']
253
260
  end
254
261
  opts.on('--compress', '=[TYPE]', 'Compress files when making packages') do |opt|
255
- @compress = opt
262
+ if opt == "no"
263
+ @compress= false
264
+ else
265
+ @compress = opt
266
+ end
256
267
  end
257
268
  opts.on('--debug', 'Print lots of messages about what tpkg is doing') do |opt|
258
269
  @debug = opt
@@ -392,6 +403,9 @@ when :upgrade
392
403
  when :remove
393
404
  tpkg = instantiate_tpkg(@tpkg_options)
394
405
  ret_val = tpkg.remove(@action_value, @other_options)
406
+ when :download
407
+ tpkg = instantiate_tpkg(@tpkg_options)
408
+ ret_val = tpkg.download_pkgs(@action_value, @other_options)
395
409
  when :verify
396
410
  result = nil
397
411
  # Verify a given .tpkg file
@@ -614,5 +628,8 @@ when :query_tpkg_metadata
614
628
  when :query_env
615
629
  puts "Operating System: #{Tpkg::get_os}"
616
630
  puts "Architecture: #{Tpkg::get_arch}"
631
+ when :query_history
632
+ tpkg = instantiate_tpkg(@tpkg_options)
633
+ tpkg.installation_history
617
634
  end
618
635
  exit ret_val
@@ -56,7 +56,7 @@ require 'kwalify' # for validating yaml
56
56
 
57
57
  class Tpkg
58
58
 
59
- VERSION = '1.23.3'
59
+ VERSION = '1.25.1'
60
60
  CONFIGDIR = '/etc'
61
61
 
62
62
  GENERIC_ERR = 1
@@ -153,7 +153,15 @@ class Tpkg
153
153
  else
154
154
  pass = passphrase
155
155
  end
156
-
156
+
157
+ # special handling for directory
158
+ if File.directory?(filename)
159
+ Find.find(filename) do |f|
160
+ encrypt(pkgname, f, pass, cipher) if File.file?(f)
161
+ end
162
+ return
163
+ end
164
+
157
165
  salt = OpenSSL::Random::random_bytes(SALT_LEN)
158
166
  c = OpenSSL::Cipher::Cipher.new(cipher)
159
167
  c.encrypt
@@ -173,6 +181,7 @@ class Tpkg
173
181
  tmpfile.close
174
182
  File.rename(tmpfile.path, filename)
175
183
  end
184
+
176
185
  # Decrypt the given file in-place.
177
186
  def self.decrypt(pkgname, filename, passphrase, cipher='aes-256-cbc')
178
187
  # passphrase can be a callback Proc, call it if that's the case
@@ -185,6 +194,13 @@ class Tpkg
185
194
  else
186
195
  pass = passphrase
187
196
  end
197
+
198
+ if File.directory?(filename)
199
+ Find.find(filename) do |f|
200
+ decrypt(pkgname, f, pass, cipher) if File.file?(f)
201
+ end
202
+ return
203
+ end
188
204
 
189
205
  file = File.open(filename)
190
206
  if (buf = file.read(MAGIC.length)) != MAGIC
@@ -250,12 +266,11 @@ class Tpkg
250
266
  else
251
267
  workdir = tempdir('tpkg', File.dirname(pkgsrcdir))
252
268
  end
253
-
254
269
  begin
255
270
  # Make the 'tpkg' directory for storing the package contents
256
271
  tpkgdir = File.join(workdir, 'tpkg')
257
272
  Dir.mkdir(tpkgdir)
258
-
273
+
259
274
  # A package really shouldn't be partially relocatable, warn the user if
260
275
  # they're creating such a scourge.
261
276
  if (File.exist?(File.join(pkgsrcdir, 'root')) && File.exist?(File.join(pkgsrcdir, 'reloc')))
@@ -267,20 +282,13 @@ class Tpkg
267
282
  # And on further reflection it makes sense to only have one chunk of
268
283
  # code (tar) ever touch the user's files.
269
284
  system("#{find_tar} -C #{pkgsrcdir} -cf - . | #{find_tar} -C #{tpkgdir} -xpf -") || raise("Package content copy failed")
270
-
285
+
271
286
  # check metadata file
272
287
  errors = []
273
- if File.exists?(File.join(tpkgdir, 'tpkg.yml'))
274
- metadata_file = File.join(tpkgdir, 'tpkg.yml')
275
- metadata_format = 'yml'
276
- elsif File.exists?(File.join(tpkgdir, 'tpkg.xml'))
277
- metadata_file = File.join(tpkgdir, 'tpkg.xml')
278
- metadata_format = 'xml'
279
- else
288
+ metadata = Metadata::instantiate_from_dir(tpkgdir)
289
+ if !metadata
280
290
  raise 'Your source directory does not contain the metadata configuration file.'
281
291
  end
282
- metadata_text = File.read(metadata_file)
283
- metadata = Metadata.new(metadata_text, metadata_format)
284
292
 
285
293
  # This is for when we're in developement mode or when installed as gem
286
294
  if File.exists?(File.join(File.dirname(File.dirname(__FILE__)), "schema"))
@@ -306,7 +314,6 @@ class Tpkg
306
314
  filemetadata = get_filemetadata_from_directory(tpkgdir)
307
315
  data = filemetadata.to_hash.recursively{|h| h.stringify_keys }
308
316
  Marshal::dump(data, file)
309
- # YAML::dump(filemetadata.to_hash, file)
310
317
  end
311
318
 
312
319
  # Check all the files are there as specified in the metadata config file
@@ -338,13 +345,13 @@ class Tpkg
338
345
 
339
346
  # Encrypt any files marked for encryption
340
347
  if tpkgfile[:encrypt]
341
- if tpkgfile[:encrypt] == 'precrypt'
348
+ if tpkgfile[:encrypt][:precrypt]
342
349
  verify_precrypt_file(working_path)
343
350
  else
344
351
  if passphrase.nil?
345
352
  raise "Package requires encryption but supplied passphrase is nil"
346
353
  end
347
- encrypt(metadata[:name], working_path, passphrase)
354
+ encrypt(metadata[:name], working_path, passphrase, *([tpkgfile[:encrypt][:algorithm]].compact))
348
355
  end
349
356
  end
350
357
  end unless metadata[:files].nil? or metadata[:files][:files].nil?
@@ -369,7 +376,10 @@ class Tpkg
369
376
  end
370
377
  File.delete(pkgfile)
371
378
  end
372
-
379
+
380
+ # update metadata file with the tpkg version
381
+ # TODO
382
+
373
383
  # Tar up the tpkg directory
374
384
  tpkgfile = File.join(package_directory, 'tpkg.tar')
375
385
  system("#{find_tar} -C #{workdir} -cf #{tpkgfile} tpkg") || raise("tpkg.tar creation failed")
@@ -444,6 +454,11 @@ class Tpkg
444
454
  next if !File.exist?(f)
445
455
  relocatable = false
446
456
 
457
+ # Append file separator at the end for directory
458
+ if File.directory?(f)
459
+ f += File::SEPARATOR
460
+ end
461
+
447
462
  # check if it's from root dir or reloc dir
448
463
  if f =~ /^#{root_dir}/
449
464
  short_fn = f[root_dir.length ..-1]
@@ -864,15 +879,42 @@ class Tpkg
864
879
  barchlength, acurrentinstallnoprefer]
865
880
  end
866
881
 
867
- def self.files_in_package(package_file)
882
+ def self.files_in_package(package_file, options = {})
883
+ file_lists = []
868
884
  files = {}
869
885
  files[:root] = []
870
886
  files[:reloc] = []
871
- topleveldir = package_toplevel_directory(package_file)
872
- extract_tpkg_tar_cmd = cmd_to_extract_tpkg_tar(package_file, topleveldir)
873
- IO.popen("#{extract_tpkg_tar_cmd} | #{find_tar} #{@@taroptions} -tf -") do |pipe|
874
- pipe.each do |file|
875
- file.chomp!
887
+
888
+ # If the metadata_directory option is available, it means this package
889
+ # has been installed and the file_metadata might be available in that directory.
890
+ # If that's the case, then parse the file_metadata to get the file list. It's
891
+ # much faster than extracting from the tar file
892
+ if metadata_directory = options[:metadata_directory]
893
+ package_name = File.basename(package_file, File.extname(package_file))
894
+ file_metadata = FileMetadata::instantiate_from_dir(File.join(metadata_directory, package_name))
895
+ end
896
+
897
+ if file_metadata
898
+ file_metadata[:files].each do |file|
899
+ if file[:relocatable]
900
+ files[:reloc] << file[:path]
901
+ else
902
+ files[:root] << file[:path]
903
+ end
904
+ end
905
+ else
906
+ topleveldir = package_toplevel_directory(package_file)
907
+ extract_tpkg_tar_cmd = cmd_to_extract_tpkg_tar(package_file, topleveldir)
908
+ IO.popen("#{extract_tpkg_tar_cmd} | #{find_tar} #{@@taroptions} -tf -") do |pipe|
909
+ pipe.each do |file|
910
+ file_lists << file.chomp!
911
+ end
912
+ end
913
+ if !$?.success?
914
+ raise "Extracting file list from #{package_file} failed"
915
+ end
916
+
917
+ file_lists.each do |file|
876
918
  if file =~ Regexp.new(File.join('tpkg', 'root'))
877
919
  files[:root] << file.sub(Regexp.new(File.join('tpkg', 'root')), '')
878
920
  elsif file =~ Regexp.new(File.join('tpkg', 'reloc', '.'))
@@ -880,9 +922,7 @@ class Tpkg
880
922
  end
881
923
  end
882
924
  end
883
- if !$?.success?
884
- raise "Extracting file list from #{package_file} failed"
885
- end
925
+
886
926
  files
887
927
  end
888
928
 
@@ -1150,7 +1190,7 @@ class Tpkg
1150
1190
  eprime.set_backtrace(e.backtrace)
1151
1191
  eprime
1152
1192
  end
1153
-
1193
+
1154
1194
  #
1155
1195
  # Instance methods
1156
1196
  #
@@ -1675,16 +1715,10 @@ class Tpkg
1675
1715
  File.join(@metadata_directory,
1676
1716
  File.basename(entry, File.extname(entry)))
1677
1717
  metadata_file = File.join(package_metadata_dir, "tpkg.yml")
1678
- m = nil
1679
- if File.exists?(metadata_file)
1680
- metadata_text = File.read(metadata_file)
1681
- m = Metadata.new(metadata_text, 'yml')
1682
- elsif File.exists?(File.join(package_metadata_dir, "tpkg.xml"))
1683
- metadata_text = File.read(File.join(package_metadata_dir, "tpkg.xml"))
1684
- m = Metadata.new(metadata_text, 'xml')
1718
+ m = Metadata::instantiate_from_dir(package_metadata_dir)
1685
1719
  # No cached metadata found, we have to extract it ourselves
1686
1720
  # and save it for next time
1687
- else
1721
+ if !m
1688
1722
  m = Tpkg::metadata_from_package(
1689
1723
  File.join(@installed_directory, entry))
1690
1724
  begin
@@ -1721,22 +1755,18 @@ class Tpkg
1721
1755
  end
1722
1756
 
1723
1757
  # Returns a hash of file_metadata for installed packages
1724
- def file_metadata_for_installed_packages
1758
+ def file_metadata_for_installed_packages(package_files = nil)
1725
1759
  ret = {}
1726
1760
 
1761
+ if package_files
1762
+ packages_files.collect!{|package_file| File.basename(package_file, File.extname(package_file))}
1763
+ end
1764
+
1727
1765
  if File.directory?(@metadata_directory)
1728
1766
  Dir.foreach(@metadata_directory) do |entry|
1729
1767
  next if entry == '.' || entry == '..'
1730
- if File.exists?(File.join(@metadata_directory, entry, "file_metadata.bin"))
1731
- file = File.join(@metadata_directory, entry, "file_metadata.bin")
1732
- file_metadata = FileMetadata.new(File.read(file), 'bin')
1733
- elsif File.exists?(File.join(@metadata_directory, entry, "file_metadata.yml"))
1734
- file = File.join(@metadata_directory, entry, "file_metadata.yml")
1735
- file_metadata = FileMetadata.new(File.read(file), 'yml')
1736
- elsif File.exists?(File.join(@metadata_directory, entry, "file_metadata.xml"))
1737
- file = File.join(@metadata_directory, entry, "file_metadata.xml")
1738
- file_metadata = FileMetadata.new(File.read(file), 'xml')
1739
- end
1768
+ next if package_files && !package_files.include?(entry)
1769
+ file_metadata = FileMetadata::instantiate_from_dir(File.join(@metadata_directory, entry))
1740
1770
  ret[file_metadata[:package_file]] = file_metadata
1741
1771
  end
1742
1772
  end
@@ -1871,10 +1901,11 @@ class Tpkg
1871
1901
  package_files << metadata[:filename]
1872
1902
  end
1873
1903
  end
1904
+
1874
1905
  metadata_for_installed_packages.each do |metadata|
1875
1906
  package_file = metadata[:filename]
1876
1907
  if package_files.include?(package_file)
1877
- fip = Tpkg::files_in_package(File.join(@installed_directory, package_file))
1908
+ fip = Tpkg::files_in_package(File.join(@installed_directory, package_file), {:metadata_directory => @metadata_directory})
1878
1909
  normalize_paths(fip)
1879
1910
  fip[:metadata] = metadata
1880
1911
  files[package_file] = fip
@@ -2206,14 +2237,13 @@ class Tpkg
2206
2237
  return {:number_of_possible_solutions_checked => number_of_possible_solutions_checked}
2207
2238
  end
2208
2239
 
2209
- def download(source, path, downloaddir = nil)
2240
+ def download(source, path, downloaddir = nil, use_cache = true)
2210
2241
  http = Tpkg::gethttp(URI.parse(source))
2211
2242
  localdir = source_to_local_directory(source)
2212
2243
  localpath = File.join(localdir, File.basename(path))
2213
-
2214
2244
  # Don't download again if file is already there from previous installation
2215
2245
  # and still has valid checksum
2216
- if File.file?(localpath)
2246
+ if File.file?(localpath) && use_cache
2217
2247
  begin
2218
2248
  Tpkg::verify_package_checksum(localpath)
2219
2249
  return localpath
@@ -2521,7 +2551,7 @@ class Tpkg
2521
2551
  if File.directory?(f)
2522
2552
  File.chown(default_dir_uid, default_dir_gid, f)
2523
2553
  else
2524
- File.chown(default_uid, default_gid, f)
2554
+ File.chown(default_uid, default_gid, f)
2525
2555
  end
2526
2556
  rescue Errno::EPERM
2527
2557
  raise if Process.euid == 0
@@ -2590,7 +2620,7 @@ class Tpkg
2590
2620
  else
2591
2621
  (1..3).each do | i |
2592
2622
  begin
2593
- Tpkg::decrypt(metadata[:name], working_path, options[:passphrase])
2623
+ Tpkg::decrypt(metadata[:name], working_path, options[:passphrase], *([tpkgfile[:encrypt][:algorithm]].compact))
2594
2624
  break
2595
2625
  rescue OpenSSL::CipherError
2596
2626
  @@passphrase = nil
@@ -2601,10 +2631,12 @@ class Tpkg
2601
2631
  end
2602
2632
  end
2603
2633
  end
2604
-
2605
- digest = Digest::SHA256.hexdigest(File.read(working_path))
2606
- # get checksum for the decrypted file. Will be used for creating file_metadata
2607
- checksums_of_decrypted_files[File.expand_path(tpkg_path)] = digest
2634
+
2635
+ if File.file?(working_path)
2636
+ digest = Digest::SHA256.hexdigest(File.read(working_path))
2637
+ # get checksum for the decrypted file. Will be used for creating file_metadata
2638
+ checksums_of_decrypted_files[File.expand_path(tpkg_path)] = digest
2639
+ end
2608
2640
  end
2609
2641
  end
2610
2642
  end if metadata[:files] && metadata[:files][:files]
@@ -2998,18 +3030,10 @@ class Tpkg
2998
3030
  package_name = File.basename(package_file, File.extname(package_file))
2999
3031
  package_metadata_dir = File.join(@metadata_directory, package_name)
3000
3032
  FileUtils.mkdir_p(package_metadata_dir)
3001
- metadata_file = File.new(File.join(package_metadata_dir, "tpkg.yml"), "w")
3002
- metadata.write(metadata_file)
3003
- metadata_file.close
3033
+ metadata.write(package_metadata_dir)
3004
3034
 
3005
3035
  # Save file_metadata for this pkg
3006
- if File.exist?(File.join(workdir, 'tpkg', 'file_metadata.bin'))
3007
- file_metadata = FileMetadata.new(File.read(File.join(workdir, 'tpkg', 'file_metadata.bin')), 'bin')
3008
- elsif File.exist?(File.join(workdir, 'tpkg', 'file_metadata.yml'))
3009
- file_metadata = FileMetadata.new(File.read(File.join(workdir, 'tpkg', 'file_metadata.yml')), 'yml')
3010
- elsif File.exists?(File.join(workdir, 'tpkg', 'file_metadata.xml'))
3011
- file_metadata = FileMetadata.new(File.read(File.join(workdir, 'tpkg', 'file_metadata.xml')), 'xml')
3012
- end
3036
+ file_metadata = FileMetadata::instantiate_from_dir(File.join(workdir, 'tpkg'))
3013
3037
  if file_metadata
3014
3038
  file_metadata[:package_file] = File.basename(package_file)
3015
3039
  file_metadata[:files].each do |file|
@@ -3230,7 +3254,6 @@ class Tpkg
3230
3254
  end
3231
3255
  end
3232
3256
  end
3233
-
3234
3257
  # The remove method actually needs !conflicts, so invert in that case
3235
3258
  if mode == CHECK_REMOVE
3236
3259
  # Flatten conflicts to an array
@@ -3617,7 +3640,6 @@ class Tpkg
3617
3640
  # in order to report back to the server
3618
3641
  already_installed_pkgs = metadata_for_installed_packages.collect{|metadata| metadata.to_hash}
3619
3642
 
3620
- installed_files = files_for_installed_packages
3621
3643
  removed_pkgs = [] # keep track of what we removed so far
3622
3644
  while pkg = solution_packages.shift
3623
3645
  if pkg[:source] == :currently_installed ||
@@ -4020,17 +4042,9 @@ class Tpkg
4020
4042
  # Extract checksum.xml from the package
4021
4043
  checksum_xml = nil
4022
4044
 
4023
- # get file_metadata.xml from the installed package
4024
- file_metadata_bin = File.join(@metadata_directory, package_full_name, 'file_metadata.bin')
4025
- file_metadata_yml = File.join(@metadata_directory, package_full_name, 'file_metadata.yml')
4026
- file_metadata_xml = File.join(@metadata_directory, package_full_name, 'file_metadata.xml')
4027
- if File.exist?(file_metadata_bin)
4028
- file_metadata = FileMetadata.new(File.read(file_metadata_bin), 'bin')
4029
- elsif File.exist?(file_metadata_yml)
4030
- file_metadata = FileMetadata.new(File.read(file_metadata_yml), 'yml')
4031
- elsif File.exist?(file_metadata_xml)
4032
- file_metadata = FileMetadata.new(File.read(file_metadata_xml), 'xml')
4033
- else
4045
+ # get file_metadata from the installed package
4046
+ file_metadata = FileMetadata::instantiate_from_dir(File.join(@metadata_directory, package_full_name))
4047
+ if !file_metadata
4034
4048
  errors = []
4035
4049
  errors << "Can't find file metadata. Most likely this is because the package was created before the verify feature was added"
4036
4050
  results[package_file] = errors
@@ -4302,6 +4316,77 @@ class Tpkg
4302
4316
  return pre_reqs
4303
4317
  end
4304
4318
 
4319
+ # print out history packages installation/remove
4320
+ def installation_history
4321
+ if !File.exists?(File.join(@log_directory,'changes.log'))
4322
+ puts "Tpkg history log does not exist."
4323
+ return GENERIC_ERR
4324
+ end
4325
+ IO.foreach(File.join(@log_directory,'changes.log')) do |line|
4326
+ puts line
4327
+ end
4328
+ end
4329
+
4330
+ # Download packages that meet the requests specified by the user.
4331
+ # Packages are downloaded into the current directory or into the directory
4332
+ # specified in options[:out]
4333
+ def download_pkgs(requests, options={})
4334
+ if options[:out]
4335
+ if !File.exists?(options[:out])
4336
+ FileUtils.mkdir_p(options[:out])
4337
+ elsif !File.directory?(options[:out])
4338
+ puts "#{options[:out]} is not a valid directory."
4339
+ return GENERIC_ERR
4340
+ end
4341
+ end
4342
+ output_dir = options[:out] || Dir.pwd
4343
+
4344
+ requirements = []
4345
+ packages = {}
4346
+ original_dir = Dir.pwd
4347
+
4348
+ workdir = Tpkg::tempdir("tpkg_download")
4349
+ Dir.chdir(workdir)
4350
+ parse_requests(requests, requirements, packages)
4351
+ packages = packages.values.flatten
4352
+ if packages.size < 1
4353
+ puts "Unable to find any packages that satisfy your request."
4354
+ Dir.chdir(original_dir)
4355
+ return GENERIC_ERR
4356
+ end
4357
+
4358
+ # Confirm with user what packages will be downloaded
4359
+ packages.delete_if{|pkg|pkg[:source] !~ /^http/}
4360
+ puts "The following packages will be downloaded:"
4361
+ packages.each do |pkg|
4362
+ puts "#{pkg[:metadata][:filename]} (source: #{pkg[:source]})"
4363
+ end
4364
+ if @@prompt && !Tpkg::confirm
4365
+ Dir.chdir(original_dir)
4366
+ return 0
4367
+ end
4368
+
4369
+ err_code = 0
4370
+ puts "Downloading to #{output_dir}"
4371
+ packages.each do |pkg|
4372
+ puts "Downloading #{pkg[:metadata][:filename]}"
4373
+ begin
4374
+ downloaded_file = download(pkg[:source], pkg[:metadata][:filename], Dir.pwd, false)
4375
+ # copy downloaded files over to destination
4376
+ FileUtils.cp(downloaded_file, output_dir)
4377
+ rescue
4378
+ warn "Warning: unable to download #{pkg[:metadata][:filename]} to #{output_dir}"
4379
+ err_code = GENERIC_ERR
4380
+ end
4381
+ end
4382
+
4383
+ # clean up working directory
4384
+ FileUtils.rm_rf(workdir)
4385
+
4386
+ Dir.chdir(original_dir)
4387
+ return err_code
4388
+ end
4389
+
4305
4390
  # TODO: figure out what other methods above can be turned into protected methods
4306
4391
  protected
4307
4392
  # log changes of pkgs that were installed/removed
@@ -242,6 +242,18 @@ class Metadata
242
242
  return metadata
243
243
  end
244
244
 
245
+ # Given the directory from which the metadata is saved, returns a Metadata
246
+ # object. The metadata file can be in yml or xml format
247
+ def self.instantiate_from_dir(dir)
248
+ metadata = nil
249
+ if File.exist?(File.join(dir, 'tpkg.yml'))
250
+ metadata = Metadata.new(File.read(File.join(dir, 'tpkg.yml')), 'yml')
251
+ elsif File.exists?(File.join(dir, 'tpkg.xml'))
252
+ metadata = Metadata.new(File.read(File.join(dir, 'tpkg.xml')), 'xml')
253
+ end
254
+ return metadata
255
+ end
256
+
245
257
  # metadata_text = text representation of the metadata
246
258
  # format = yml, xml, json, etc.
247
259
  def initialize(metadata_text, format, source=nil)
@@ -279,17 +291,43 @@ class Metadata
279
291
  end
280
292
  end
281
293
  end if @hash[:dependencies]
294
+
295
+ @hash[:files][:files].each do |file|
296
+ # We need to do this for backward compatibility. In the old yml schema,
297
+ # the encrypt field can either be "true" or a string value. Now, it is
298
+ # a hash. We need to use a hash because we need to store info like the
299
+ # encryption algorithm.
300
+ if file[:encrypt] && !file[:encrypt].is_a?(Hash)
301
+ precrypt = true if file[:encrypt] == 'precrypt'
302
+ file[:encrypt] = {:precrypt => precrypt}
303
+ end
304
+ # perms value are octal, but kwalify might treat it as decimal if it's something like 4550
305
+ # the user might also use string instead of number
306
+ if file[:posix] && file[:posix][:perms] &&
307
+ (file[:posix][:perms].is_a?(String) or file[:posix][:perms] >= 1000)
308
+ file[:posix][:perms] = "#{file[:posix][:perms]}".oct
309
+ end
310
+ end if @hash[:files] && @hash[:files][:files]
282
311
  else
283
312
  @hash = metadata_xml_to_hash.with_indifferent_access
284
313
  end
285
314
  return @hash
286
315
  end
287
316
 
288
- def write(file)
289
- # When we convert xml to hash, we store the key as symbol. So when we
290
- # write back out to file, we should stringify all the keys for readability.
291
- data = to_hash.recursively{|h| h.stringify_keys }
292
- YAML::dump(data, file)
317
+ # Write the metadata to a file under the specified directory
318
+ # The file will be saved as tpkg.yml or tpkg.xml.
319
+ def write(dir, retain_format=false)
320
+ file = nil
321
+ if retain_format && @format == 'xml'
322
+ puts "TODO"
323
+ else
324
+ file = File.new(File.join(dir, "tpkg.yml"), "w")
325
+ # When we convert xml to hash, we store the key as symbol. So when we
326
+ # write back out to file, we should stringify all the keys for readability.
327
+ data = to_hash.recursively{|h| h.stringify_keys }
328
+ YAML::dump(data, file)
329
+ end
330
+ file.close
293
331
  end
294
332
 
295
333
  def generate_package_filename
@@ -559,10 +597,13 @@ class Metadata
559
597
  file = {}
560
598
  file[:path] = filexml.elements['path'].text
561
599
  if filexml.elements['encrypt']
562
- encrypt = true
600
+ encrypt = {}
563
601
  if filexml.elements['encrypt'].attribute('precrypt') &&
564
602
  filexml.elements['encrypt'].attribute('precrypt').value == 'true'
565
- encrypt = "precrypt"
603
+ encrypt['precrypt'] = true
604
+ end
605
+ if filexml.elements['encrypt'].attribute('algorithm')
606
+ encrypt['algorithm'] = filexml.elements['encrypt'].attribute('algorithm').value
566
607
  end
567
608
  file[:encrypt] = encrypt
568
609
  end
@@ -618,6 +659,20 @@ class Metadata
618
659
  end
619
660
 
620
661
  class FileMetadata < Metadata
662
+ # Given the directory from which the file_metadata is saved, returns a FileMetadata
663
+ # object. The file_metadata file can be in binary, yaml or xml.
664
+ def self.instantiate_from_dir(dir)
665
+ file_metadata = nil
666
+ if File.exist?(File.join(dir, 'file_metadata.bin'))
667
+ file_metadata = FileMetadata.new(File.read(File.join(dir, 'file_metadata.bin')), 'bin')
668
+ elsif File.exist?(File.join(dir, 'file_metadata.yml'))
669
+ file_metadata = FileMetadata.new(File.read(File.join(dir, 'file_metadata.yml')), 'yml')
670
+ elsif File.exists?(File.join(dir, 'file_metadata.xml'))
671
+ file_metadata = FileMetadata.new(File.read(File.join(dir, 'file_metadata.xml')), 'xml')
672
+ end
673
+ return file_metadata
674
+ end
675
+
621
676
  def to_hash
622
677
  if @hash
623
678
  return @hash
@@ -0,0 +1,91 @@
1
+ type: map
2
+ mapping:
3
+ "schema_file": { type: text }
4
+ "name": { type: str, required: yes }
5
+ "version": { type: text, required: yes }
6
+ "package_version": { type: text }
7
+ "maintainer": { type: str, required: yes }
8
+ "operatingsystem": { type: seq, sequence: [ {type: str} ] }
9
+ "architecture": { type: seq, sequence: [ {type: str} ] }
10
+ "description": { type: str }
11
+ "bugreporting": { type: str }
12
+ "dependencies":
13
+ type: seq
14
+ sequence:
15
+ - type: map
16
+ mapping:
17
+ "name": { type: str, required: yes }
18
+ "minimum_version": { type: text }
19
+ "maximum_version": { type: text }
20
+ "minimum_package_version": { type: text }
21
+ "maximum_package_version": { type: text }
22
+ "allowed_versions": { type: text }
23
+ "native": { type: bool }
24
+ "type": { type: any, pattern: /(native|tpkg)$/ }
25
+ "conflicts":
26
+ type: seq
27
+ sequence:
28
+ - type: map
29
+ mapping:
30
+ "name": { type: str, required: yes }
31
+ "minimum_version": { type: text }
32
+ "maximum_version": { type: text }
33
+ "minimum_package_version": { type: text }
34
+ "maximum_package_version": { type: text }
35
+ "native": { type: bool }
36
+ "type": { type: any, pattern: /(native|tpkg)$/ }
37
+ "externals":
38
+ type: seq
39
+ sequence:
40
+ - type: map
41
+ mapping:
42
+ "name": { type: text, required: yes }
43
+ "data": { type: text }
44
+ "datascript": { type: text }
45
+ "datafile": { type: text }
46
+ "files":
47
+ type: map
48
+ mapping:
49
+ "file_defaults":
50
+ type: map
51
+ mapping:
52
+ "posix":
53
+ type: map
54
+ mapping:
55
+ "owner": { type: text }
56
+ "group": { type: text }
57
+ "perms": { type: text }
58
+ "dirs_defaults":
59
+ type: map
60
+ mapping:
61
+ "posix":
62
+ type: map
63
+ mapping:
64
+ "owner": { type: text }
65
+ "group": { type: text }
66
+ "perms": { type: text }
67
+ "files":
68
+ type: seq
69
+ sequence:
70
+ - type: map
71
+ mapping:
72
+ "path": { type: text, required: yes }
73
+ "encrypt":
74
+ type: map
75
+ mapping:
76
+ "algorithm": { type: text }
77
+ "precrypt": { type: any, pattern: /^true$|^false$/ }
78
+ "init":
79
+ type: map
80
+ mapping:
81
+ "start": { type: int }
82
+ "levels": { type: seq, sequence: [ { type: int } ] }
83
+ "crontab":
84
+ type: map
85
+ mapping: { "user": { type: str } }
86
+ "posix":
87
+ type: map
88
+ mapping: { "owner": { type: text },
89
+ "group": { type: text },
90
+ "perms": { type: text } }
91
+
@@ -70,7 +70,11 @@ mapping:
70
70
  - type: map
71
71
  mapping:
72
72
  "path": { type: text, required: yes }
73
- "encrypt": { type: any, pattern: /^true$|^precrypt$/ }
73
+ "encrypt":
74
+ type: map
75
+ mapping:
76
+ "algorithm": { type: text }
77
+ "precrypt": { type: any, pattern: /^true$|^false$/ }
74
78
  "init":
75
79
  type: map
76
80
  mapping:
@@ -0,0 +1,43 @@
1
+ <!ELEMENT tpkg (name, version, package_version?, maintainer+, operatingsystem*, architecture*, description?, bugreporting?, dependencies?, externals?, files?)>
2
+
3
+ <!ELEMENT name (#PCDATA)>
4
+ <!ELEMENT version (#PCDATA)>
5
+ <!ELEMENT package_version (#PCDATA)>
6
+ <!ELEMENT maintainer (#PCDATA)>
7
+ <!ELEMENT operatingsystem (#PCDATA)>
8
+ <!ELEMENT architecture (#PCDATA)>
9
+ <!ELEMENT description (#PCDATA)>
10
+ <!ELEMENT bugreporting (#PCDATA)>
11
+
12
+ <!ELEMENT dependencies (dependency*)>
13
+ <!ELEMENT dependency (name, minimum_version?, maximum_version?, minimum_package_version?, maximum_package_version?, allowed_versions?, native?)>
14
+ <!ELEMENT minimum_version (#PCDATA)>
15
+ <!ELEMENT maximum_version (#PCDATA)>
16
+ <!ELEMENT minimum_package_version (#PCDATA)>
17
+ <!ELEMENT maximum_package_version (#PCDATA)>
18
+ <!ELEMENT allowed_versions (#PCDATA)>
19
+ <!ELEMENT native EMPTY>
20
+
21
+ <!ELEMENT externals (external*)>
22
+ <!ELEMENT external (name, (data|datafile|datascript))>
23
+ <!ELEMENT data (#PCDATA)>
24
+ <!ELEMENT datafile (#PCDATA)>
25
+ <!ELEMENT datascript (#PCDATA)>
26
+
27
+ <!ELEMENT files (file_defaults?, file*)>
28
+ <!ELEMENT file_defaults (posix?)>
29
+ <!ELEMENT posix (owner?, group?, perms?)>
30
+ <!ELEMENT owner (#PCDATA)>
31
+ <!ELEMENT group (#PCDATA)>
32
+ <!ELEMENT perms (#PCDATA)>
33
+ <!ELEMENT file (path, encrypt?, init?, crontab?, posix?)>
34
+ <!ELEMENT path (#PCDATA)>
35
+ <!ELEMENT encrypt EMPTY>
36
+ <!ATTLIST encrypt precrypt (true|false) #IMPLIED>
37
+ <!ATTLIST encrypt algorithm CDATA #IMPLIED>
38
+ <!ELEMENT init (start?, levels?)>
39
+ <!ELEMENT start (#PCDATA)>
40
+ <!ELEMENT levels (#PCDATA)>
41
+ <!ELEMENT crontab (user?)>
42
+ <!ELEMENT user (#PCDATA)>
43
+
@@ -34,6 +34,7 @@
34
34
  <!ELEMENT path (#PCDATA)>
35
35
  <!ELEMENT encrypt EMPTY>
36
36
  <!ATTLIST encrypt precrypt (true|false) #IMPLIED>
37
+ <!ATTLIST encrypt algorithm CDATA #IMPLIED>
37
38
  <!ELEMENT init (start?, levels?)>
38
39
  <!ELEMENT start (#PCDATA)>
39
40
  <!ELEMENT levels (#PCDATA)>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tpkg
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.23.3
4
+ version: 1.25.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darren Dao
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-05-20 00:00:00 +00:00
13
+ date: 2010-07-14 00:00:00 +00:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -63,8 +63,10 @@ files:
63
63
  - schema/tpkg-1.0.4.dtd
64
64
  - schema/tpkg-1.0.0.dtd
65
65
  - schema/tpkg-1.0.5.dtd
66
+ - schema/schema-1.0.7.yml
66
67
  - schema/tpkg.dtd
67
68
  - schema/tpkg-1.0.1.dtd
69
+ - schema/tpkg-1.0.7.dtd
68
70
  - schema/tpkg-1.0.3.dtd
69
71
  - schema/schema.yml
70
72
  - schema/tpkg-1.0.2.dtd