lyp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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