jss-api 0.5.8 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. data/CHANGES.md +55 -7
  2. data/README.md +2 -1
  3. data/bin/cgrouper +1 -1
  4. data/bin/subnet-update +1 -1
  5. data/lib/jss-api.rb +2 -363
  6. data/lib/jss-api/api_connection.rb +78 -15
  7. data/lib/jss-api/api_object.rb +1 -1
  8. data/lib/jss-api/api_object/advanced_search.rb +1 -1
  9. data/lib/jss-api/api_object/advanced_search/advanced_computer_search.rb +1 -1
  10. data/lib/jss-api/api_object/advanced_search/advanced_mobile_device_search.rb +1 -1
  11. data/lib/jss-api/api_object/advanced_search/advanced_user_search.rb +1 -1
  12. data/lib/jss-api/api_object/building.rb +1 -1
  13. data/lib/jss-api/api_object/category.rb +1 -1
  14. data/lib/jss-api/api_object/computer.rb +1 -1
  15. data/lib/jss-api/api_object/creatable.rb +1 -1
  16. data/lib/jss-api/api_object/criteriable.rb +1 -1
  17. data/lib/jss-api/api_object/criteriable/criteria.rb +1 -1
  18. data/lib/jss-api/api_object/criteriable/criterion.rb +1 -1
  19. data/lib/jss-api/api_object/department.rb +1 -1
  20. data/lib/jss-api/api_object/distribution_point.rb +92 -22
  21. data/lib/jss-api/api_object/extendable.rb +1 -1
  22. data/lib/jss-api/api_object/extension_attribute.rb +1 -1
  23. data/lib/jss-api/api_object/extension_attribute/computer_extension_attribute.rb +1 -1
  24. data/lib/jss-api/api_object/extension_attribute/mobile_device_extension_attribute.rb +1 -1
  25. data/lib/jss-api/api_object/extension_attribute/user_extension_attribute.rb +1 -1
  26. data/lib/jss-api/api_object/group.rb +1 -1
  27. data/lib/jss-api/api_object/group/computer_group.rb +1 -1
  28. data/lib/jss-api/api_object/group/mobile_device_group.rb +1 -1
  29. data/lib/jss-api/api_object/group/user_group.rb +1 -1
  30. data/lib/jss-api/api_object/ldap_server.rb +1 -1
  31. data/lib/jss-api/api_object/locatable.rb +1 -1
  32. data/lib/jss-api/api_object/matchable.rb +1 -1
  33. data/lib/jss-api/api_object/mobile_device.rb +1 -1
  34. data/lib/jss-api/api_object/netboot_server.rb +1 -1
  35. data/lib/jss-api/api_object/network_segment.rb +1 -1
  36. data/lib/jss-api/api_object/osx_configuration_profile.rb +1 -1
  37. data/lib/jss-api/api_object/package.rb +117 -64
  38. data/lib/jss-api/api_object/peripheral.rb +1 -1
  39. data/lib/jss-api/api_object/peripheral_type.rb +1 -1
  40. data/lib/jss-api/api_object/policy.rb +1 -1
  41. data/lib/jss-api/api_object/purchasable.rb +1 -1
  42. data/lib/jss-api/api_object/removable_macaddr.rb +1 -1
  43. data/lib/jss-api/api_object/scopable.rb +1 -1
  44. data/lib/jss-api/api_object/scopable/scope.rb +1 -1
  45. data/lib/jss-api/api_object/script.rb +1 -1
  46. data/lib/jss-api/api_object/self_servable.rb +1 -1
  47. data/lib/jss-api/api_object/site.rb +1 -1
  48. data/lib/jss-api/api_object/software_update_server.rb +1 -1
  49. data/lib/jss-api/api_object/updatable.rb +1 -1
  50. data/lib/jss-api/api_object/uploadable.rb +1 -1
  51. data/lib/jss-api/api_object/user.rb +1 -1
  52. data/lib/jss-api/client.rb +22 -21
  53. data/lib/jss-api/compatibility.rb +1 -1
  54. data/lib/jss-api/composer.rb +2 -2
  55. data/lib/jss-api/configuration.rb +1 -1
  56. data/lib/jss-api/db_connection.rb +63 -12
  57. data/lib/jss-api/exceptions.rb +1 -1
  58. data/lib/jss-api/ruby_extensions.rb +1 -1
  59. data/lib/jss-api/ruby_extensions/filetest.rb +1 -1
  60. data/lib/jss-api/ruby_extensions/hash.rb +1 -1
  61. data/lib/jss-api/ruby_extensions/ipaddr.rb +1 -1
  62. data/lib/jss-api/ruby_extensions/pathname.rb +1 -1
  63. data/lib/jss-api/ruby_extensions/string.rb +17 -1
  64. data/lib/jss-api/ruby_extensions/time.rb +1 -1
  65. data/lib/jss-api/server.rb +1 -1
  66. data/lib/jss-api/utility.rb +416 -0
  67. data/lib/jss-api/version.rb +8 -8
  68. metadata +3 -2
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,4 +1,4 @@
1
- ### Copyright 2014 Pixar
1
+ ### Copyright 2016 Pixar
2
2
  ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
@@ -1,25 +1,25 @@
1
- ### Copyright 2014 Pixar
2
- ###
1
+ ### Copyright 2016 Pixar
2
+ ###
3
3
  ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
4
  ### with the following modification; you may not use this file except in
5
5
  ### compliance with the Apache License and the following modification to it:
6
6
  ### Section 6. Trademarks. is deleted and replaced with:
7
- ###
7
+ ###
8
8
  ### 6. Trademarks. This License does not grant permission to use the trade
9
9
  ### names, trademarks, service marks, or product names of the Licensor
10
10
  ### and its affiliates, except as required to comply with Section 4(c) of
11
11
  ### the License and to reproduce the content of the NOTICE file.
12
- ###
12
+ ###
13
13
  ### You may obtain a copy of the Apache License at
14
- ###
14
+ ###
15
15
  ### http://www.apache.org/licenses/LICENSE-2.0
16
- ###
16
+ ###
17
17
  ### Unless required by applicable law or agreed to in writing, software
18
18
  ### distributed under the Apache License with the above modification is
19
19
  ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
20
  ### KIND, either express or implied. See the Apache License for the specific
21
21
  ### language governing permissions and limitations under the Apache License.
22
- ###
22
+ ###
23
23
  ###
24
24
 
25
25
  ###
@@ -86,6 +86,8 @@ module JSS
86
86
  ### The possible values for cpu_type (required_processor) in a JSS package
87
87
  CPU_TYPES = ["None", "x86", "ppc"]
88
88
 
89
+ # TO DO - this is redundant with DEFAULT_PROCESSOR, but both are in use
90
+ # clean them up!
89
91
  ### which is default? there must be one to make a new pkg
90
92
  DEFAULT_CPU_TYPE = "None"
91
93
 
@@ -115,10 +117,10 @@ module JSS
115
117
 
116
118
  ### @return [String] the filename of the .pkg, .mpkg, or .dmg on the Casper server
117
119
  attr_reader :filename
118
-
119
- ### @return [Pathname] the local receipt when this pkg is installed
120
+
121
+ ### @return [Pathname] the local receipt when this pkg is installed
120
122
  attr_reader :receipt
121
-
123
+
122
124
  ### @return [Boolean] does this item 'Fill Existing Users' when jamf installs it?
123
125
  attr_reader :fill_existing_users
124
126
 
@@ -130,16 +132,16 @@ module JSS
130
132
 
131
133
  ### @return [Array<String>] the OS versions this can be installed onto. For all minor versions, the format is 10.5.x
132
134
  attr_reader :os_requirements
133
-
135
+
134
136
  ### @return [String] limit installation to these architectures: 'x86', 'ppc', 'None'
135
137
  attr_reader :required_processor
136
-
138
+
137
139
  ### @return [String] the name of a pkg to install (or "Do Not Install") when this pkg can't be installed
138
140
  attr_reader :switch_with_package
139
141
 
140
142
  ### @return [Boolean] can this item be uninstalled? Some, e.g. OS Updates, can't
141
143
  attr_reader :allow_uninstalled
142
-
144
+
143
145
  ### @return [String] the category of this pkg, stored in the JSS as the id number from the categories table
144
146
  attr_reader :category
145
147
 
@@ -151,16 +153,16 @@ module JSS
151
153
 
152
154
  ### @return [Boolean] only install this pkg if it's available in the commandline softwareupdate.
153
155
  attr_reader :install_if_reported_available
154
-
156
+
155
157
  ### @return [Boolean] should this pkg be installed on the boot volume during imaging
156
158
  attr_reader :boot_volume_required
157
-
159
+
158
160
  ### @return [Integer] Priority to use for deploying or uninstalling the package
159
161
  attr_reader :priority
160
162
 
161
163
  ### @return [Boolean] does this pkg cause a notification to be sent on self-heal?
162
164
  attr_reader :send_notification
163
-
165
+
164
166
 
165
167
  ###
166
168
  ### @see JSS::APIObject#initialize
@@ -173,6 +175,7 @@ module JSS
173
175
  @allow_uninstalled = @init_data[:allow_uninstalled]
174
176
  @boot_volume_required = @init_data[:boot_volume_required]
175
177
  @category = JSS::APIObject.get_name(@init_data[:category])
178
+ @category = nil if @category.to_s.casecmp("No category assigned") == 0
176
179
  @filename = @init_data[:filename] || @init_data[:name]
177
180
  @fill_existing_users = @init_data[:fill_existing_users]
178
181
  @fill_user_template = @init_data[:fill_user_template]
@@ -185,12 +188,12 @@ module JSS
185
188
  @priority = @init_data[:priority] || DEFAULT_PRIORITY
186
189
  @reboot_required = @init_data[:reboot_required]
187
190
  @required_processor = @init_data[:required_processor] || DEFAULT_CPU_TYPE
191
+ @required_processor = nil if @required_processor.to_s.casecmp('none') == 0
188
192
  @send_notification = @init_data[:send_notification]
189
193
  @switch_with_package = @init_data[:switch_with_package] || DO_NOT_INSTALL
190
-
194
+
191
195
  # the receipt is the filename with any .zip extension removed.
192
- @receipt = @filname ? (JSS::Client::RECEIPTS_FOLDER + @filname.to_s.sub(/.zip$/, '')) : nil
193
-
196
+ @receipt = @filename ? (JSS::Client::RECEIPTS_FOLDER + @filename.to_s.sub(/.zip$/, '')) : nil
194
197
  end # init
195
198
 
196
199
 
@@ -478,7 +481,7 @@ module JSS
478
481
  def installed?
479
482
  @receipt.file?
480
483
  end
481
-
484
+
482
485
  ###
483
486
  ### Upload a locally-readable file to the master distribution point.
484
487
  ### If the file is a directory (like a bundle .pk/.mpkg) it will be zipped before
@@ -489,7 +492,7 @@ module JSS
489
492
  ###
490
493
  ### @param local_file_path[String,Pathname] the local path to the file to be uploaded
491
494
  ###
492
- ### @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
495
+ ### @param rw_pw[String,Symbol] the password for the read/write account on the master Distribution Point,
493
496
  ### or :prompt, or :stdin# where # is the line of stdin containing the password See {JSS::DistributionPoint#mount}
494
497
  ###
495
498
  ### @param unmount[Boolean] whether or not ot unount the distribution point when finished.
@@ -499,7 +502,7 @@ module JSS
499
502
  def upload_master_file (local_file_path, rw_pw, unmount = true)
500
503
 
501
504
  raise JSS::NoSuchItemError, "Please create this package in the JSS before uploading it." unless @in_jss
502
-
505
+
503
506
  mdp = JSS::DistributionPoint.master_distribution_point
504
507
  destination = mdp.mount(rw_pw, :rw) +"#{DIST_POINT_PKGS_FOLDER}/#{@filename}"
505
508
 
@@ -534,11 +537,11 @@ module JSS
534
537
  local_path = zipfile
535
538
 
536
539
  self.filename = zipfile.basename.to_s
537
-
540
+
538
541
  end # if directory
539
542
  self.update
540
543
  FileUtils.copy_entry local_path, destination
541
-
544
+
542
545
  mdp.unmount if unmount
543
546
  end # upload
544
547
 
@@ -569,21 +572,23 @@ module JSS
569
572
  end # delete master file
570
573
 
571
574
 
575
+ ### Install this package via the jamf binary 'install' command from the
576
+ ### distribution point for this machine.
577
+ ### See {JSS::DistributionPoint.my_distribution_point}
572
578
  ###
573
579
  ### @note This code must be run as root to install packages
574
580
  ###
575
- ### Causes the pkg/dmg to be installed via the jamf binary 'install' command from the
576
- ### distribution point for this machine. See {JSS::DistributionPoint.my_distribution_point}
577
- ###
578
- ### The read-only or http passwd for the dist. point must be provided, except for
579
- ### non-authenticated http downloads)
581
+ ### The read-only or http passwd for the dist. point must be provided,
582
+ ### except for non-authenticated http downloads)
580
583
  ###
581
584
  ### @param args[Hash] the arguments for installation
582
585
  ###
583
- ### @option args :ro_pw[String] the read-only or http password for the distribution point for the
584
- ### local machine (http will be used if available, and may not need a pw)
586
+ ### @option args :ro_pw[String] the read-only or http password for the
587
+ ### distribution point for the local machine
588
+ ### (http will be used if available, and may not need a pw)
585
589
  ###
586
- ### @option args :target[String,Pathname] The drive on which to install the package, defaults to '/'
590
+ ### @option args :target[String,Pathname] The drive on which to install
591
+ ### the package, defaults to '/'
587
592
  ###
588
593
  ### @option args :verbose [Boolean] be verbose to stdout, defaults to false
589
594
  ###
@@ -591,14 +596,21 @@ module JSS
591
596
  ###
592
597
  ### @option args :fut[Boolean] fill user template, defaults to false
593
598
  ###
594
- ### @option args :unmount[Boolean] unmount the distribution point when finished?(if we mounted it),
595
- ### defaults to false
599
+ ### @option args :unmount[Boolean] unmount the distribution point when
600
+ ### finished?(if we mounted it), defaults to false
601
+ ###
602
+ ### @option args :no_http[Boolean] don't use http downloads even if they
603
+ ### are enabled for the dist. point.
596
604
  ###
597
- ### @option args :no_http[Boolean] don't use http downloads even if they are enabled for the dist. point.
605
+ ### @option args :alt_download_url [String] Use this url for an http
606
+ ### download, regardless of distribution point settings. This can be used
607
+ ### to access Cloud Distribution Points if the fileshare isn't available.
608
+ ### The URL should already be ur
609
+ ### The package filename will be removed or appended as needed.
598
610
  ###
599
- ### @return [Process::Status] the final status of the jamf binary command
611
+ ### @return [Boolean] did the jamf install succeed?
600
612
  ###
601
- ### @todo deal with cert-based https authentication
613
+ ### @todo deal with cert-based https authentication in dist points
602
614
  ###
603
615
  def install (args = {})
604
616
 
@@ -608,46 +620,73 @@ module JSS
608
620
 
609
621
  ro_pw = args[:ro_pw]
610
622
 
611
- mdp = JSS::DistributionPoint.my_distribution_point
612
-
613
- ### how do we access our dist. point? with http?
614
- if mdp.http_downloads_enabled and (not args[:no_http])
615
- using_http = true
616
- src_path = mdp.http_url
617
- if mdp.username_password_required
618
- raise JSS::MissingDataError, "No password provided for http download" unless ro_pw
619
- raise JSS::InvaldDatatError, "Incorrect password for http access to distribution point." unless mdp.check_pw(:http, ro_pw)
620
- # insert the name and pw into the uri
621
- reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]") # we'll escape all the chars that aren't unreserved
622
- src_path = src_path.sub(%r{(https?://)(\S)}, "#{$1}#{URI.escape mdp.http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@#{$2}")
623
+ # as of Casper 9.72, with http downloads, the jamf binary requires
624
+ # the filename must be at the end of the -path url, but before 9.72
625
+ # it can't be.
626
+ # e.g.
627
+ # in <9.72: jamf install -package foo.pkg -path http://mycasper.myorg.edu/CasperShare/Packages
628
+ # but
629
+ # in >=9.72: jamf install -package foo.pkg -path http://mycasper.myorg.edu/CasperShare/Packages/foo.pkg
630
+ #
631
+ append_at_vers = JSS.parse_jss_version("9.72")[:version]
632
+ our_vers = JSS.parse_jss_version(JSS::API.server.raw_version)[:version]
633
+ no_filename_in_url = (our_vers < append_at_vers)
634
+
635
+ # use a provided alternative url for an http download
636
+ if args[:alt_download_url]
637
+
638
+ # we'll re-add the filename below if needed.
639
+ src_path = args[:alt_download_url].chomp "/#{@filename}"
640
+
641
+ # use our appropriate dist. point for download
642
+ else
643
+ mdp = JSS::DistributionPoint.my_distribution_point
644
+
645
+ ### how do we access our dist. point? with http?
646
+ if mdp.http_downloads_enabled and (not args[:no_http])
647
+ using_http = true
648
+ src_path = mdp.http_url
649
+ if mdp.username_password_required
650
+ raise JSS::MissingDataError, "No password provided for http download" unless ro_pw
651
+ raise JSS::InvaldDatatError, "Incorrect password for http access to distribution point." unless mdp.check_pw(:http, ro_pw)
652
+ # insert the name and pw into the uri
653
+ reserved_chars = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}]") # we'll escape all the chars that aren't unreserved
654
+ src_path = src_path.sub(%r{(https?://)(\S)}, "#{$1}#{URI.escape mdp.http_username,reserved_chars}:#{URI.escape ro_pw, reserved_chars}@#{$2}")
655
+ end
656
+
657
+ # or with filesharing?
658
+ else
659
+ using_http = false
660
+ src_path = mdp.mount(ro_pw)
623
661
  end
624
662
 
625
- # or with filesharing?
626
- else
627
- using_http = false
628
- src_path = mdp.mount(ro_pw)
629
- end
663
+ # look at the pkgs folder
664
+ src_path += "#{DIST_POINT_PKGS_FOLDER}"
665
+ end # if args[:alt_download_url]
666
+
667
+ src_path += "/#{@filename}" unless no_filename_in_url
630
668
 
631
- # look at the pkgs folder
632
- src_path += "/#{DIST_POINT_PKGS_FOLDER}"
633
669
 
634
670
  ### are we doing "fill existing users" or "fill user template"?
635
671
  do_feu = args[:feu] ? "-feu" : ""
636
672
  do_fut = args[:fut] ? "-fut" : ""
637
673
 
638
674
  ### the install args for jamf
639
- command_args = "-package '#{@filename}' -path '#{src_path}' -target '#{args[:target]}' #{do_feu} #{do_fut} -showProgress -verbose ; echo jamfexit $?"
675
+ command_args = "-package '#{@filename}' -path '#{src_path}' -target '#{args[:target]}' #{do_feu} #{do_fut} -showProgress -verbose"
640
676
 
641
- ### run it via a client
677
+ ### run it via a client cmd
642
678
  install_out = JSS::Client.run_jamf :install, command_args, args[:verbose]
643
679
 
644
- install_exit = $?
680
+ install_out =~ %r{<exitCode>(\d+)</exitCode>}
681
+ install_exit = $1 ? $1.to_i : nil
682
+ install_exit ||= $?.exitstatus
683
+
645
684
 
646
685
  if (args.include? :unmount)
647
686
  mdp.unmount unless using_http
648
687
  end
649
688
 
650
- return install_exit
689
+ return install_exit == 0 ? true : false
651
690
  end
652
691
 
653
692
  ###
@@ -668,7 +707,7 @@ module JSS
668
707
  ### @return [Process::Status] the result of the 'jamf uninstall' command
669
708
  ###
670
709
  def uninstall (args = {})
671
-
710
+
672
711
  raise JSS::UnsupportedError, \
673
712
  "This package cannot be uninstalled. Please use CasperAdmin to index it and allow uninstalls" unless removable?
674
713
  raise JSS::UnsupportedError, "You must have root privileges to uninstall packages" unless JSS.superuser?
@@ -689,6 +728,18 @@ module JSS
689
728
 
690
729
 
691
730
 
731
+ ### What type of package is this?
732
+ ###
733
+ ### @return [Symbol] :pkg or :dmg or:unknown
734
+ ###
735
+ def type
736
+ case @filename
737
+ when /\.m?pkg(\.zip)?$/ then :pkg
738
+ when /\.dmg$/ then :dmg
739
+ else :unknown
740
+ end
741
+ end
742
+
692
743
 
693
744
  ################################
694
745
  ### Private Instance Methods
@@ -706,7 +757,7 @@ module JSS
706
757
  pkg = doc.add_element "package"
707
758
  pkg.add_element('allow_uninstalled').text = @allow_uninstalled
708
759
  pkg.add_element('boot_volume_required').text = @boot_volume_required
709
- pkg.add_element('category').text = @category
760
+ pkg.add_element('category').text = @category.to_s.casecmp("No category assigned") == 0 ? "" : @category
710
761
  pkg.add_element('filename').text = @filename
711
762
  pkg.add_element('fill_existing_users').text = @fill_existing_users
712
763
  pkg.add_element('fill_user_template').text = @fill_user_template
@@ -717,7 +768,7 @@ module JSS
717
768
  pkg.add_element('os_requirements').text = JSS.to_s_and_a(@os_requirements)[:stringform]
718
769
  pkg.add_element('priority').text = @priority
719
770
  pkg.add_element('reboot_required').text = @reboot_required
720
- pkg.add_element('required_processor').text = @required_processor
771
+ pkg.add_element('required_processor').text = @required_processor.to_s.empty? ? "None" : @required_processor
721
772
  pkg.add_element('send_notification').text = @send_notification
722
773
  pkg.add_element('switch_with_package').text = @switch_with_package
723
774
  return doc.to_s
@@ -741,7 +792,7 @@ module JSS
741
792
  alias boot boot_volume_required
742
793
  alias boot? boot_volume_required
743
794
  alias notify send_notification
744
-
795
+
745
796
  alias removable= allow_uninstalled=
746
797
  alias boot= boot_volume_required=
747
798
  alias feu= fill_existing_users=
@@ -754,6 +805,8 @@ module JSS
754
805
 
755
806
 
756
807
 
808
+
809
+
757
810
  end # class Package
758
811
 
759
812
  end # module jss