lyp 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 381c017e254a433f1b75547cfbe8d775edd1b620
4
+ data.tar.gz: 522058c1cbed06a7d28ef1b04cd1d88d68b5be9b
5
+ SHA512:
6
+ metadata.gz: 9f4452b8c6d711749aa7b81afe594401321e61afdc1eb914c8b8dc49608e7230a44886be47cb7aec57738613d4ac2300a7596ad407d88e4e173e88660b2269d7
7
+ data.tar.gz: b390a85bcb6a7e5f2e7fae3b903705546c63a066086be50f8903f59f95bd983fc855c5c1f5a6ad05e8fa03ffc5947ca26daae1b881b3ec934cddc9b81cc86915
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Sharon Rosner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,9 @@
1
+ [![Build Status](https://travis-ci.org/ciconia/lyp.svg?branch=master)](https://travis-ci.org/ciconia/lyp)
2
+
3
+ # lyp
4
+
5
+ lyp is a package manager for lilypond.
6
+
7
+ Initial spec is [here](https://github.com/ciconia/lyp/wiki/General-spec).
8
+
9
+
data/bin/lilypond ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path("../lib/lyp/version", File.dirname(__FILE__))
4
+
5
+ require File.expand_path("../lib/lyp/directories", File.dirname(__FILE__))
6
+ require File.expand_path("../lib/lyp/settings", File.dirname(__FILE__))
7
+ require File.expand_path("../lib/lyp/lilypond", File.dirname(__FILE__))
8
+
9
+ lilypond_path = Lyp::Lilypond.current_lilypond
10
+
11
+ if (ARGV == ['-v']) || (ARGV == ['--warranty'])
12
+ puts "Lyp version #{Lyp::VERSION}"
13
+ # Show lilypond version and exit
14
+ exec("#{lilypond_path} #{ARGV.join(' ')}")
15
+ end
16
+
17
+ if ARGV.size == 0
18
+ exec(lilypond_path)
19
+ else
20
+
21
+ begin
22
+ Lyp::Lilypond.compile(ARGV)
23
+ rescue => e
24
+ STDERR.puts e.message
25
+ exit 1
26
+ end
27
+ end
data/bin/lyp ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "lyp/cli"
4
+
data/lib/lyp.rb ADDED
@@ -0,0 +1,16 @@
1
+ %w{
2
+ output
3
+ env
4
+
5
+ directories
6
+ settings
7
+
8
+ template
9
+ resolver
10
+ wrapper
11
+
12
+ package
13
+ lilypond
14
+ }.each do |f|
15
+ require File.expand_path("lyp/#{f}", File.dirname(__FILE__))
16
+ end
data/lib/lyp/cli.rb ADDED
@@ -0,0 +1,32 @@
1
+ require "lyp"
2
+ require "lyp/version"
3
+
4
+ INSTALL_MSG = <<EOF
5
+ Lyp is currently not installed. In order to use lyp, ~/.lyp/bin has to
6
+ be included in the shell $PATH.
7
+ EOF
8
+
9
+ # test installation
10
+ unless Lyp::ENV.installed?
11
+ require 'highline'
12
+
13
+ cli = HighLine.new
14
+ STDERR.puts INSTALL_MSG.gsub("\n", " ")
15
+
16
+ if cli.agree("Would you like to install lyp now? (yes/no)")
17
+ Lyp::ENV.install!
18
+ STDERR.puts "To finish installation please open a new shell"
19
+ exit
20
+ end
21
+ end
22
+
23
+ require 'commander/import'
24
+
25
+ program :name, 'lyp'
26
+ program :version, Lyp::VERSION
27
+ program :description, 'Lyp is a package manager for lilypond.'
28
+ program :help_formatter, :compact
29
+
30
+ require 'lyp/cli/commands'
31
+
32
+ default_command(:list)
@@ -0,0 +1,146 @@
1
+ # package commands
2
+
3
+ def lilypond_prefix(info)
4
+ if info[:current] && info[:default]
5
+ "=* "
6
+ elsif info[:current]
7
+ "=> "
8
+ elsif info[:default]
9
+ " * "
10
+ else
11
+ " "
12
+ end
13
+ end
14
+
15
+ def lilypond_postfix(info)
16
+ if info[:system]
17
+ " (system)"
18
+ else
19
+ ""
20
+ end
21
+ end
22
+
23
+ def format_lilypond_entry(info)
24
+ "#{lilypond_prefix(info)}#{info[:version]}#{lilypond_postfix(info)}"
25
+ end
26
+
27
+ LILYPOND_PREAMBLE = <<EOF
28
+
29
+ Lilypond versions:
30
+
31
+ EOF
32
+
33
+ LILYPOND_LEGEND = <<EOF
34
+
35
+ # => - current
36
+ # =* - current && default
37
+ # * - default
38
+
39
+ EOF
40
+
41
+ command :list do |c|
42
+ c.syntax = "list [PATTERN]"
43
+ c.description = "Lists installed versions of packages whose name matches PATTERN"
44
+ c.action do |args, opts|
45
+ pattern = args.first
46
+ if pattern.nil? || pattern == 'lilypond'
47
+ STDOUT.puts LILYPOND_PREAMBLE
48
+ Lyp::Lilypond.list.each {|info| puts format_lilypond_entry(info)}
49
+ STDOUT.puts LILYPOND_LEGEND
50
+ else
51
+ Lyp::Package.list(args.first).each {|p| puts p}
52
+ end
53
+ end
54
+ end
55
+
56
+ command :compile do |c|
57
+ c.syntax = "compile <FILE>"
58
+ c.description = "Resolves package dependencies and invokes lilypond"
59
+ c.action do |args, opts|
60
+ begin
61
+ raise "File not specified" if args.empty?
62
+ Lyp::Lilypond.compile(ARGV[1..-1])
63
+ rescue => e
64
+ STDERR.puts e.message
65
+ exit 1
66
+ end
67
+ end
68
+ end
69
+
70
+ command :search do |c|
71
+ c.syntax = "search <PATTERN>"
72
+ c.description = "Search for a package or a version of lilypond"
73
+ c.action do |args, opts|
74
+ pattern = args.first
75
+ if pattern == 'lilypond'
76
+ begin
77
+ versions = Lyp::Lilypond.search
78
+ versions.each {|v| puts v}
79
+ rescue => e
80
+ STDERR.puts e.message
81
+ exit 1
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ command :install do |c|
88
+ c.syntax = "install <PACKAGE...>"
89
+ c.description = "Install a package or a version of lilypond"
90
+ c.option "-d", "--default", "Set default version"
91
+ c.action do |args, opts|
92
+ begin
93
+ raise "No package specified" if args.empty?
94
+
95
+ args.each do |package|
96
+ if package =~ /^lilypond(?:@(.+))?$/
97
+ Lyp::Lilypond.install($1, opts.__hash__)
98
+ end
99
+ end
100
+ rescue => e
101
+ STDERR.puts e.message
102
+ exit 1
103
+ end
104
+ end
105
+ end
106
+
107
+ command :use do |c|
108
+ c.syntax = "use [lilypond@]<VERSION>"
109
+ c.description = "Switch version of lilypond"
110
+ c.option "-d", "--default", "Set default version"
111
+
112
+ c.action do |args, opts|
113
+ begin
114
+ version = args.first
115
+ if version =~ /^lilypond@(.+)$/
116
+ version = $1
117
+ end
118
+
119
+ lilypond = Lyp::Lilypond.use(version, opts.__hash__)
120
+ puts "Using version #{lilypond[:version]}"
121
+ rescue => e
122
+ STDERR.puts e.message
123
+ exit 1
124
+ end
125
+ end
126
+ end
127
+
128
+ command :uninstall do |c|
129
+ c.syntax = "uninstall <PACKAGE>"
130
+ c.description = "Uninstall a package or version of lilypond"
131
+
132
+ c.action do |args, opts|
133
+ begin
134
+ raise "No package specified" if args.empty?
135
+
136
+ args.each do |package|
137
+ if package =~ /^lilypond(?:@(.+))?$/
138
+ Lyp::Lilypond.uninstall($1)
139
+ end
140
+ end
141
+ rescue => e
142
+ STDERR.puts e.message
143
+ exit 1
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,26 @@
1
+ module Lyp
2
+ # A package specifier is of the form <package>@<version specifier>, where
3
+ # the version specifier can be simply a version number, or include an operator
4
+ # before the version number. Accepted operators: >=, ~>
5
+ PACKAGE_RE = /^([^@]+)(?:@(.+))?$/
6
+
7
+ LYPACK_DIRECTORY = File.expand_path('~/.lyp')
8
+ LYPACK_BIN_DIRECTORY = File.join(LYPACK_DIRECTORY, 'bin')
9
+ DEFAULT_PACKAGE_DIRECTORY = File.join(LYPACK_DIRECTORY, 'packages')
10
+ DEFAULT_LILYPONDS_DIRECTORY = File.join(LYPACK_DIRECTORY, 'lilyponds')
11
+
12
+ SETTINGS_FILENAME = 'settings.yml'
13
+
14
+ def self.packages_dir
15
+ DEFAULT_PACKAGE_DIRECTORY
16
+ end
17
+
18
+ def self.lilyponds_dir
19
+ DEFAULT_LILYPONDS_DIRECTORY
20
+ end
21
+
22
+ def self.settings_file
23
+ File.join(LYPACK_DIRECTORY, SETTINGS_FILENAME)
24
+ end
25
+ end
26
+
data/lib/lyp/env.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Lyp::ENV
2
+ class << self
3
+ PROFILE_FILES = %w{
4
+ .profile .bash_profile .bash_login .bashrc .zshenv .zshrc .mkshrc
5
+ }.map {|fn| File.join(Dir.home, fn)}
6
+
7
+ LYPACK_LOAD_CODE = <<EOF
8
+
9
+ [[ ":${PATH}:" == *":${HOME}/.lyp/bin:"* ]] || PATH="$HOME/.lyp/bin:$PATH"
10
+ EOF
11
+
12
+ def install!
13
+ # Install lyp in environment
14
+
15
+ PROFILE_FILES.each do |fn|
16
+ next unless File.file?(fn)
17
+ unless IO.read(fn) =~ /\.lyp\/bin/
18
+ begin
19
+ File.open(fn, 'a') {|f| f << LYPACK_LOAD_CODE}
20
+ rescue
21
+ # ignore
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def installed?
28
+ ":#{::ENV['PATH']}:" =~ /#{Lyp::LYPACK_BIN_DIRECTORY}/
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,377 @@
1
+ require 'httpclient'
2
+ require 'uri'
3
+
4
+ module Lyp::Lilypond
5
+ class << self
6
+ def compile(argv)
7
+ fn = Lyp.wrap(argv.pop)
8
+ argv << fn
9
+
10
+ invoke(argv)
11
+ exec("#{current_lilypond} #{argv.join(' ')}")
12
+ end
13
+
14
+ def invoke(argv)
15
+ lilypond = detect_use_version_argument(argv) || current_lilypond
16
+
17
+ exec("#{lilypond} #{argv.join(' ')}")
18
+ end
19
+
20
+ def detect_use_version_argument(argv)
21
+ nil
22
+ end
23
+
24
+ def default_lilypond
25
+ Lyp::Settings['lilypond/default']
26
+ end
27
+
28
+ def set_default_lilypond(path)
29
+ Lyp::Settings['lilypond/default'] = path
30
+ end
31
+
32
+ # The current lilypond path is stored in a temporary file named by the
33
+ # session id. Thus we can persist the version selected by the user
34
+ def current_lilypond
35
+ settings = get_session_settings
36
+
37
+ if !settings[:current]
38
+ settings[:current] = default_lilypond
39
+ set_session_settings(settings)
40
+ end
41
+
42
+ settings[:current]
43
+ end
44
+
45
+ def set_current_lilypond(path)
46
+ settings = get_session_settings
47
+ settings[:current] = path
48
+ set_session_settings(settings)
49
+ end
50
+
51
+ def get_session_settings
52
+ YAML.load(IO.read(session_settings_filename)) rescue {}
53
+ end
54
+
55
+ def set_session_settings(settings)
56
+ File.open(session_settings_filename, 'w+') do |f|
57
+ f << YAML.dump(settings)
58
+ end
59
+ end
60
+
61
+ def session_settings_filename
62
+ "/tmp/lyp.session.#{Process.getsid}.yml"
63
+ end
64
+
65
+ CMP_VERSION = proc do |x, y|
66
+ Gem::Version.new(x[:version]) <=> Gem::Version.new(y[:version])
67
+ end
68
+
69
+ def list
70
+ system_list = system_lilyponds
71
+ lyp_list = lyp_lilyponds
72
+
73
+ default = default_lilypond
74
+ unless default
75
+ latest = system_list.sort(&CMP_VERSION).last || lyp_list.sort(&CMP_VERSION).last
76
+ if latest
77
+ default = latest[:path]
78
+ set_default_lilypond(default)
79
+ end
80
+ end
81
+ current = current_lilypond
82
+
83
+ lilyponds = system_list + lyp_list
84
+
85
+ lilyponds.each do |l|
86
+ l[:default] = l[:path] == default
87
+ l[:current] = l[:path] == current
88
+ end
89
+
90
+ # sort by version
91
+ lilyponds.sort!(&CMP_VERSION)
92
+ end
93
+
94
+ def lyp_lilyponds
95
+ list = []
96
+
97
+ Dir["#{Lyp.lilyponds_dir}/*"].each do |path|
98
+ next unless File.directory?(path) && File.basename(path) =~ /^[\d\.]+$/
99
+
100
+ version = File.basename(path)
101
+ path = File.join(path, "bin/lilypond")
102
+ list << {
103
+ path: path,
104
+ version: version
105
+ }
106
+ end
107
+
108
+ list
109
+ end
110
+
111
+ def system_lilyponds
112
+ list = get_system_lilyponds_paths
113
+ return list if list.empty?
114
+
115
+ list.inject([]) do |m, path|
116
+ begin
117
+ resp = `#{path} -v`
118
+ if resp.lines.first =~ /LilyPond ([0-9\.]+)/i
119
+ m << {
120
+ path: path,
121
+ version: $1,
122
+ system: true
123
+ }
124
+ end
125
+ rescue
126
+ # ignore error
127
+ end
128
+ m
129
+ end
130
+ end
131
+
132
+ def get_system_lilyponds_paths
133
+ list = `which -a lilypond`
134
+ list = list.lines.map {|f| f.chomp}.reject do |l|
135
+ l =~ /^#{Lyp::LYPACK_BIN_DIRECTORY}/
136
+ end
137
+ end
138
+
139
+ BASE_URL = "http://download.linuxaudio.org/lilypond/binaries"
140
+
141
+ # Returns a list of versions of lilyponds available for download
142
+ def search
143
+ require 'open-uri'
144
+ require 'nokogiri'
145
+
146
+ platform = detect_lilypond_platform
147
+ url = "#{BASE_URL}/#{platform}/"
148
+ doc = Nokogiri::HTML(open(url))
149
+
150
+ versions = []
151
+ doc.xpath("//td//a").each do |a|
152
+ if a[:href] =~ /^lilypond-([0-9\.]+)/
153
+ versions << $1
154
+ end
155
+ end
156
+ versions
157
+ end
158
+
159
+ def latest_stable_version
160
+ search.reverse.find {|l| Gem::Version.new(l).segments[1] % 2 == 0}
161
+ end
162
+
163
+ def latest_unstable_version
164
+ search.reverse.find {|l| Gem::Version.new(l).segments[1] % 2 != 0}
165
+ end
166
+
167
+ def latest_version
168
+ search.last
169
+ end
170
+
171
+ def install(version_specifier, opts = {})
172
+ version = detect_version_from_specifier(version_specifier)
173
+ raise "No version found matching specifier #{version_specifier}" unless version
174
+
175
+ install_version(version, opts)
176
+
177
+ lilypond_path = "#{Lyp.lilyponds_dir}/#{version}/bin/lilypond"
178
+ set_current_lilypond(lilypond_path)
179
+ set_default_lilypond(lilypond_path) if opts[:default]
180
+ end
181
+
182
+ def detect_version_from_specifier(version_specifier)
183
+ case version_specifier
184
+ when /^\d/
185
+ version_specifier
186
+ when 'stable'
187
+ latest_stable_version
188
+ when 'unstable'
189
+ latest_unstable_version
190
+ else
191
+ req = Gem::Requirement.new(version_specifier)
192
+ search.reverse.find {|v| req =~ Gem::Version.new(v)}
193
+ end
194
+ rescue => e
195
+ raise "Invalid version specified: #{version_specifier}"
196
+ end
197
+
198
+ def detect_lilypond_platform
199
+ case RUBY_PLATFORM
200
+ when /x86_64-darwin/
201
+ "darwin-x86"
202
+ when /ppc-darwin/
203
+ "darwin-ppc"
204
+ when "i686-linux"
205
+ "linux-x86"
206
+ when "x86_64-linux"
207
+ "linux-64"
208
+ when "ppc-linux"
209
+ "linux-ppc"
210
+ end
211
+ end
212
+
213
+ def install_version(version, opts)
214
+ platform = detect_lilypond_platform
215
+ url = lilypond_install_url(platform, version, opts)
216
+ fn = temp_install_filename(url)
217
+
218
+ download_lilypond(url, fn, opts) unless File.file?(fn)
219
+ install_lilypond_files(fn, platform, version, opts)
220
+ end
221
+
222
+ def lilypond_install_url(platform, version, opts)
223
+ ext = platform =~ /darwin/ ? ".tar.bz2" : ".sh"
224
+ filename = "lilypond-#{version}-1.#{platform}"
225
+
226
+ "#{BASE_URL}/#{platform}/#{filename}#{ext}"
227
+ end
228
+
229
+ def temp_install_filename(url)
230
+ u = URI(url)
231
+ "/tmp/lyp-installer-#{File.basename(u.path)}"
232
+ end
233
+
234
+ def download_lilypond(url, fn, opts)
235
+ STDERR.puts "Downloading #{url}" unless opts[:silent]
236
+
237
+ download_count = 0
238
+ client = HTTPClient.new
239
+ conn = client.get_async(url)
240
+ msg = conn.pop
241
+ total_size = msg.header['Content-Length'].first.to_i
242
+ io = msg.content
243
+
244
+ unless opts[:silent]
245
+ pbar = ProgressBar.create(title: 'Download', total: total_size)
246
+ end
247
+ File.open(fn, 'w+') do |f|
248
+ while data = io.read(10000)
249
+ download_count += data.bytesize
250
+ f << data
251
+ unless opts[:silent]
252
+ pbar.progress = download_count if download_count <= total_size
253
+ end
254
+ end
255
+ end
256
+ pbar.finish unless opts[:silent]
257
+ end
258
+
259
+ def install_lilypond_files(fn, platform, version, opts)
260
+ case platform
261
+ when /darwin/
262
+ install_lilypond_files_osx(fn, version, opts)
263
+ when /linux/
264
+ install_lilypond_files_linux(fn, platform, version, opts)
265
+ end
266
+ end
267
+
268
+ def install_lilypond_files_osx(fn, version, opts)
269
+ target = "/tmp/lyp/installer/lilypond"
270
+ FileUtils.mkdir_p(target)
271
+
272
+ STDERR.puts "Extracting..." unless opts[:silent]
273
+ exec "tar -xjf #{fn} -C #{target}"
274
+
275
+ copy_lilypond_files("#{target}/LilyPond.app/Contents/Resources", version, opts)
276
+ end
277
+
278
+ def install_lilypond_files_linux(fn, platform, version, opts)
279
+ target = "/tmp/lyp/installer/lilypond"
280
+ FileUtils.mkdir_p(target)
281
+
282
+ # create temp directory in which to untar file
283
+ tmp_dir = "/tmp/lyp/#{Time.now.to_f}"
284
+ FileUtils.mkdir_p(tmp_dir)
285
+
286
+ FileUtils.cd(tmp_dir) do
287
+ exec "sh #{fn} --tarball"
288
+ end
289
+
290
+ tmp_fn = "#{tmp_dir}/lilypond-#{version}-1.#{platform}.tar.bz2"
291
+
292
+ STDERR.puts "Extracting..." unless opts[:silent]
293
+ exec "tar -xjf #{tmp_fn} -C #{target}"
294
+
295
+ copy_lilypond_files("#{target}/usr", version, opts)
296
+ end
297
+
298
+ def copy_lilypond_files(base_path, version, opts)
299
+ target_dir = File.join(Lyp.lilyponds_dir, version)
300
+
301
+ FileUtils.rm_rf(target_dir) if File.exists?(target_dir)
302
+
303
+ # create directory for lilypond files
304
+ FileUtils.mkdir_p(target_dir)
305
+
306
+ # copy files
307
+ STDERR.puts "Copying..." unless opts[:silent]
308
+ %w{bin etc lib lib64 share var}.each do |entry|
309
+ dir = File.join(base_path, entry)
310
+ FileUtils.cp_r(dir, target_dir, remove_destination: true) if File.directory?(dir)
311
+ end
312
+
313
+ STDERR.puts exec "#{target_dir}/bin/lilypond -v" unless opts[:silent]
314
+ rescue => e
315
+ puts e.message
316
+ end
317
+
318
+ def use(version, opts)
319
+ lilypond_list = list.reverse
320
+
321
+ case version
322
+ when 'system'
323
+ lilypond = lilypond_list.find {|v| v[:system] }
324
+ unless lilypond
325
+ raise "Could not find a system installed version of lilypond"
326
+ end
327
+ when 'latest'
328
+ lilypond = lilypond_list.first
329
+ when 'stable'
330
+ lilypond = lilypond_list.find do |v|
331
+ Gem::Version.new(v[:version]).segments[1] % 2 == 0
332
+ end
333
+ when 'unstable'
334
+ lilypond = lilypond_list.find do |v|
335
+ Gem::Version.new(v[:version]).segments[1] % 2 != 0
336
+ end
337
+ else
338
+ version = "~>#{version}.0" if version =~ /^\d+\.\d+$/
339
+ req = Gem::Requirement.new(version)
340
+ lilypond = lilypond_list.find {|v| req =~ Gem::Version.new(v[:version])}
341
+ end
342
+
343
+ unless lilypond
344
+ raise "Could not find a lilypond matching \"#{version}\""
345
+ end
346
+
347
+ set_current_lilypond(lilypond[:path])
348
+ set_default_lilypond(lilypond[:path]) if opts[:default]
349
+
350
+ lilypond
351
+ end
352
+
353
+ def uninstall(version)
354
+ lilyponds = list.reverse
355
+ lilypond = lilyponds.find {|l| l[:version] == version && !l[:system]}
356
+ unless lilypond
357
+ raise "Invalid version specified: #{version}"
358
+ end
359
+ lilyponds.delete(lilypond)
360
+ latest = lilyponds.first
361
+
362
+ if lilypond[:default]
363
+ set_default_lilypond(latest && latest[:path])
364
+ end
365
+ if lilypond[:current]
366
+ set_current_lilypond(latest && latest[:path])
367
+ end
368
+
369
+ lilypond_dir = File.expand_path('../..', lilypond[:path])
370
+ FileUtils.rm_rf(lilypond_dir)
371
+ end
372
+
373
+ def exec(cmd)
374
+ raise unless system(cmd)
375
+ end
376
+ end
377
+ end