Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions libraries/plistbuddy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module MacOS
module PlistBuddyHelpers
def convert_to_string_from_data_type(value)
data_type_cases = { Array => "array #{value}",
Integer => "int #{value}",
TrueClass => "bool #{value}",
FalseClass => "bool #{value}",
Hash => "dict #{value}",
String => "string #{value}",
Float => "float #{value}" }
data_type_cases[value.class]
end

def format_plistbuddy_command(action_property, plist_entry, plist_value = nil)
plist_value = args_formatter(action_property, plist_value)
"/usr/libexec/Plistbuddy -c \'#{action_property.to_s.capitalize} :#{plist_entry} #{plist_value}\'"
end

private

def args_formatter(action_property, plist_value)
if action_property == :add
convert_to_string_from_data_type plist_value
else
plist_value
end
end
end
end

Chef::Recipe.include(MacOS::PlistBuddyHelpers)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given some of the method names here are not super specific (args_formatter), maybe the PlistBuddy resource should import these instead?

Copy link
Collaborator Author

@americanhanko americanhanko Oct 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean. I probably should've set args_formatter to private, but regardless, that method exists only to add the data type if the Add command is called.

Copy link
Collaborator Author

@americanhanko americanhanko Nov 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've set args_formatter to private, which I think makes sense given the usage.

I think extracting the plistbuddy test cookbook to an entire test cookbook is outside the scope of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Chef::Resource.include(MacOS::PlistBuddyHelpers)
34 changes: 34 additions & 0 deletions resources/plistbuddy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
resource_name :plistbuddy

property :path, String, name_property: true
property :entry, String, required: true
property :value, [Hash, String, Array, TrueClass, FalseClass, Integer, Float]

default_action :set

action_class do
def entry_missing?
command = format_plistbuddy_command(:print, new_resource.entry, new_resource.value)
full_command = command + ' ' + new_resource.path
shell_out(full_command).error?
end

def current_entry_value
command = format_plistbuddy_command(:print, new_resource.entry)
full_command = command + ' ' + new_resource.path
shell_out(full_command).stdout.chomp
end
end

action :set do
if entry_missing?
execute format_plistbuddy_command(:add, new_resource.entry, new_resource.value) + ' ' + new_resource.path
execute format_plistbuddy_command(:set, new_resource.entry, new_resource.value) + ' ' + new_resource.path
elsif current_entry_value != new_resource.value.to_s
execute format_plistbuddy_command(:set, new_resource.entry, new_resource.value) + ' ' + new_resource.path
end
end

action :delete do
execute format_plistbuddy_command(:delete, new_resource.entry, new_resource.value) + ' ' + new_resource.path
end
3 changes: 3 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
require 'chefspec'
require 'chefspec/berkshelf'

require_relative '../libraries/plistbuddy'
require_relative '../libraries/xcode'
55 changes: 55 additions & 0 deletions spec/unit/libraries/plistbuddy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'spec_helper'

include MacOS::PlistBuddyHelpers

describe MacOS::PlistBuddyHelpers, '#format_plistbuddy_command' do
context 'Adding a value to a plist' do
it 'the bool arguments contain the data type' do
expect(format_plistbuddy_command(:add, 'FooEntry', true)).to eq "/usr/libexec/Plistbuddy -c 'Add :FooEntry bool true'"
end

it 'the int arguments contain the data type' do
expect(format_plistbuddy_command(:add, 'QuuxEntry', 50)).to eq "/usr/libexec/Plistbuddy -c 'Add :QuuxEntry int 50'"
end

it 'the delete command is formatted properly' do
expect(format_plistbuddy_command(:delete, 'BarEntry')).to eq "/usr/libexec/Plistbuddy -c 'Delete :BarEntry '"
end

it 'the set command is formatted properly' do
expect(format_plistbuddy_command(:set, 'BazEntry', false)).to eq "/usr/libexec/Plistbuddy -c 'Set :BazEntry false'"
end

it 'the print command is formatted properly' do
expect(format_plistbuddy_command(:print, 'QuxEntry')).to eq "/usr/libexec/Plistbuddy -c 'Print :QuxEntry '"
end
end
end

describe MacOS::PlistBuddyHelpers, '#convert_to_string_from_data_type' do
context 'When given a certain data type' do
it 'returns the required PlistBuddy boolean entry' do
expect(convert_to_string_from_data_type(true)).to eq 'bool true'
end

xit 'returns the required PlistBuddy array entry' do # TODO: Implement proper plist array syntax (i.e. containers)
expect(convert_to_string_from_data_type(%w(foo bar))).to eq 'array foo bar'
end

xit 'returns the required PlistBuddy dictionary entry' do # TODO: Implement proper plist dict syntax (i.e. containers)
expect(convert_to_string_from_data_type('baz' => 'qux')).to eq 'dict key value'
end

it 'returns the required PlistBuddy string entry' do
expect(convert_to_string_from_data_type('quux')).to eq 'string quux'
end

it 'returns the required PlistBuddy int entry' do
expect(convert_to_string_from_data_type(1)).to eq 'int 1'
end

it 'returns the required PlistBuddy float entry' do
expect(convert_to_string_from_data_type(1.0)).to eq 'float 1.0'
end
end
end
14 changes: 14 additions & 0 deletions spec/unit/recipes/plistbuddy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'spec_helper'

describe 'macos::default' do
context 'When all attributes are default, on macOS 10.12' do
let(:chef_run) do
runner = ChefSpec::ServerRunner.new(platform: 'mac_os_x', version: '10.12')
runner.converge(described_recipe)
end

it 'converges successfully' do
expect { chef_run }.to_not raise_error
end
end
end
103 changes: 103 additions & 0 deletions test/cookbooks/plistbuddy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
*~
*#
.#*
\#*#
.*.sw[a-z]
*.un~

# Bundler
Gemfile
Gemfile.lock
bin/*
.bundle/*

# test kitchen
.kitchen/
.kitchen.local.yml

# Chef
Berksfile.lock
.zero-knife.rb
Policyfile.lock.json
.autotest
coverage
.DS_Store
pkg/*
tags
*/tags
.chef
results

# You should check in your Gemfile.lock in applications, and not in gems
external_tests/*.lock
/Gemfile.local

# ignore some common Bundler 'binstubs' directory names
# http://gembundler.com/man/bundle-exec.1.html
b/
binstubs/
.bundle
# RVM and RBENV ruby version files
.rbenv-version
.rvmrc
.ruby-version
.ruby-gemset

# IDE files
.project

# Documentation
_site/*
.yardoc/
doc/

# Kitchen Tests Local Mode Data
kitchen-tests/nodes/*

# Temporary files present during spec runs
spec/data/test-dir
spec/data/nodes
/config/

# acceptance binstubs
acceptance/bin/*

vendor/
acceptance/vendor
kitchen-tests/vendor

# Visual Studio Code files
.vscode
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
.idea

# CMake
cmake-build-debug/

## File-based project format:
*.iws

## Plugin-specific files:

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Testing
*.box
berks-cookbooks
Vagrantfile
.rubocop.yml
.vagrant
data_bags
5 changes: 5 additions & 0 deletions test/cookbooks/plistbuddy/Berksfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
source 'https://supermarket.chef.io'

metadata

cookbook 'macos', path: '../../../../macos/'
4 changes: 4 additions & 0 deletions test/cookbooks/plistbuddy/metadata.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name 'plistbuddy'
version '1.0.0'

depends 'macos', '0.8.4'
4 changes: 4 additions & 0 deletions test/cookbooks/plistbuddy/recipes/customize_dock.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
plistbuddy '/Users/vagrant/Library/Preferences/com.apple.dock.plist' do
entry 'showMissionControlGestureEnabled'
value false
end
2 changes: 2 additions & 0 deletions test/cookbooks/plistbuddy/recipes/default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include_recipe 'plistbuddy::customize_dock'
include_recipe 'plistbuddy::show_hidden_files'
4 changes: 4 additions & 0 deletions test/cookbooks/plistbuddy/recipes/show_hidden_files.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
plistbuddy '/Users/vagrant/Library/Preferences/com.apple.finder.plist' do
entry 'AppleShowAllFiles'
value true
end
7 changes: 7 additions & 0 deletions test/cookbooks/plistbuddy/test/smoke/default/default_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
describe command("/usr/libexec/PlistBuddy -c 'Print :showMissionControlGestureEnabled' /Users/vagrant/Library/Preferences/com.apple.dock.plist") do
its('stdout') { should match 'false' }
end

describe command("/usr/libexec/PlistBuddy -c 'Print :AppleShowAllFiles' /Users/vagrant/Library/Preferences/com.apple.finder.plist") do
its('stdout') { should match 'true' }
end
2 changes: 1 addition & 1 deletion test/smoke/default/xcode_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
end

describe command('/usr/local/bin/xcversion simulators') do
its('stdout') { should match /iOS 10\.3\.1 Simulator \(installed\)/ }
its('stdout') { should match(/iOS 10\.3\.1 Simulator \(installed\)/) }
end
end