lydown 0.10.0 → 0.12.4

Sign up to get free protection for your applications and to get access to all the features.
data/bin/lydown CHANGED
@@ -2,4 +2,8 @@
2
2
 
3
3
  require 'lydown/cli'
4
4
 
5
- Lydown::CLI::Commands.start(ARGV)
5
+ if ARGV.empty?
6
+ Lydown::CLI::REPL.run
7
+ else
8
+ Lydown::CLI::Commands.start(ARGV)
9
+ end
@@ -1,5 +1,4 @@
1
1
  require 'digest/md5'
2
- require 'msgpack'
3
2
 
4
3
  module Cache
5
4
  class << self
@@ -26,7 +25,7 @@ module Cache
26
25
 
27
26
  def calculate_hash(*params)
28
27
  params.map do |p|
29
- Digest::MD5.hexdigest(p.is_a?(String) ? p : p.to_msgpack)
28
+ Digest::MD5.hexdigest(p.is_a?(String) ? p : p.to_s)
30
29
  end.join('-')
31
30
  end
32
31
 
@@ -9,5 +9,7 @@ require 'lydown/cli/proofing'
9
9
  require 'lydown/cli/diff'
10
10
  require 'lydown/cli/translation'
11
11
  require 'lydown/cli/output'
12
+ require 'lydown/cli/repl'
13
+ require 'lydown/cli/installer'
12
14
  require 'lydown/cli/commands'
13
15
  require 'lydown/cli/signals'
@@ -5,15 +5,19 @@ module Lydown::CLI
5
5
  desc "version", "show Lydown version"
6
6
  def version
7
7
  require 'lydown/version'
8
+ $stderr.puts "Lydown version #{Lydown::VERSION}"
8
9
 
9
- puts "Lydown version #{Lydown::VERSION}"
10
- exit!(0)
10
+ lilypond_version = Lydown::CLI::Support.detect_lilypond_version(false)
11
+ if lilypond_version
12
+ $stderr.puts "Lilypond version #{lilypond_version}"
13
+ end
11
14
  end
12
-
15
+
13
16
  desc "compile [PATH]", "compile the lydown source at PATH"
14
17
  method_option :format, aliases: '-f',
15
18
  default: 'pdf', desc: 'Set output format (pdf/png/ly/midi/mp3)',
16
19
  enum: %w{pdf png ly midi mp3}
20
+ method_option :pdf, type: :boolean, desc: 'Set PDF output format'
17
21
  method_option :png, type: :boolean, desc: 'Set PNG output format'
18
22
  method_option :ly, type: :boolean, desc: 'Set Lilypond output format'
19
23
  method_option :midi, type: :boolean, desc: 'Set MIDI output format'
@@ -35,14 +39,23 @@ module Lydown::CLI
35
39
  desc: 'Create separate file for each movement'
36
40
  method_option :verbose, type: :boolean
37
41
  def compile(*args)
42
+ path = args.first || '.'
43
+
44
+ # check if user specified a command as an argument (e.g. --version)
45
+ if (path =~ /^\-\-(\w+)/) && respond_to?($1)
46
+ return send($1)
47
+ end
48
+
49
+ Lydown::CLI::Support.detect_lilypond_version(true)
50
+
38
51
  require 'lydown'
39
52
 
40
53
  opts = Lydown::CLI::Support.copy_options(options)
41
- opts[:path] = args.first || '.'
54
+ opts[:path] = path
42
55
 
43
56
  # Set format based on direct flag
44
57
  opts[:format] = opts[:format].to_sym if opts[:format]
45
- [:png, :ly, :midi, :mp3].each {|f| opts[:format] = f if opts[f]}
58
+ [:pdf, :png, :ly, :midi, :mp3].each {|f| opts[:format] = f if opts[f]}
46
59
 
47
60
  opts[:parts] = opts[:parts].split(',') if opts[:parts]
48
61
  opts[:movements] = opts[:movements].split(',') if opts[:movements]
@@ -51,8 +64,6 @@ module Lydown::CLI
51
64
  Lydown::CLI::Support.detect_work_directory(opts)
52
65
  Lydown::CLI::Support.detect_filename(opts)
53
66
 
54
- p opts
55
-
56
67
  if (opts[:format] == :midi) || (opts[:format] == :mp3)
57
68
  opts[:score_only] = true
58
69
  opts[:parts_only] = false
@@ -77,6 +88,8 @@ module Lydown::CLI
77
88
  enum: %w{pdf png ly}
78
89
  method_option :include_parts, aliases: '-i', desc: 'Include parts (comma separated)'
79
90
  def proof(*args)
91
+ Lydown::CLI::Support.detect_lilypond_version(true)
92
+
80
93
  require 'lydown'
81
94
 
82
95
  opts = Lydown::CLI::Support.copy_options(options)
@@ -102,6 +115,11 @@ module Lydown::CLI
102
115
  Lydown::CLI::Translation.process(opts)
103
116
  end
104
117
 
118
+ desc "install [PACKAGE] [VERSION]", "install a package"
119
+ def install(*args)
120
+ Lydown::CLI::Installer.install(*args)
121
+ end
122
+
105
123
  def method_missing(method, *args)
106
124
  args = ["compile", method.to_s] + args
107
125
  self.class.start(args)
@@ -18,16 +18,26 @@ module Lydown::CLI::Compiler
18
18
  }
19
19
 
20
20
  def process(opts)
21
- t1 = Time.now
21
+ @start_time = Time.now
22
22
 
23
23
  opts = opts.deep_clone
24
24
  work = create_work_from_opts(opts)
25
25
 
26
26
  jobs = create_jobs_from_opts(work, opts)
27
+
28
+ # check if no jobs were created. This could happen when lydown processes
29
+ # parts but no parts are found
30
+ if jobs[:compile].empty?
31
+ $stderr.puts "No parts found."
32
+ return
33
+ end
34
+
27
35
  process_jobs(work, jobs, opts)
28
36
 
29
- t2 = Time.now
30
- $stderr.puts "Elapsed: #{'%.1f' % [t2-t1]}s"
37
+ now = Time.now
38
+ unless opts[:silent] || opts[:format] == :midi
39
+ $stderr.puts "Elapsed: #{'%.1f' % [now - @start_time]}s"
40
+ end
31
41
  end
32
42
 
33
43
  def create_jobs_from_opts(work, opts)
@@ -212,7 +222,7 @@ module Lydown::CLI::Compiler
212
222
  end
213
223
 
214
224
  def open_target(opts)
215
- filename = "#{opts[:output_target]}.#{opts[:format]}"
225
+ filename = "#{opts[:output_target]}.#{opts[:format] || 'pdf'}"
216
226
 
217
227
  unless File.file?(filename)
218
228
  filename2 = "#{opts[:output_target]}-page1.#{opts[:format]}"
@@ -224,18 +234,31 @@ module Lydown::CLI::Compiler
224
234
  end
225
235
 
226
236
  if opts[:format] == :midi
227
- open_midi_target(filename)
237
+ open_midi_target(filename, opts)
228
238
  else
229
239
  system("open #{filename}")
230
240
  end
231
241
  end
232
242
 
233
- def open_midi_target(filename)
243
+ def open_midi_target(filename, opts)
244
+ now = Time.now
245
+ unless opts[:silent]
246
+ $stderr.puts "Elapsed: #{'%.1f' % [now - @start_time]}s"
247
+ end
248
+
234
249
  $stderr << "Playing #{filename}..."
235
250
  Open3.popen2e("timidity #{filename}") do |input, output, wait_thr|
236
- input.close
237
- output.read
238
- output.close
251
+ begin
252
+ prev_handler = trap("INT") do
253
+ Process.kill("INT", wait_thr.pid)
254
+ prev_handler.call if prev_handler
255
+ end
256
+ input.close
257
+ output.read
258
+ output.close
259
+ ensure
260
+ trap("INT", prev_handler)
261
+ end
239
262
  end
240
263
  end
241
264
  end
@@ -18,7 +18,7 @@ module Lydown::CLI::Diff
18
18
  set_cached_content(path, read_content(path)) rescue nil
19
19
  count += 1
20
20
  end
21
- $stderr.puts "Cached #{count} files."
21
+ # $stderr.puts "Cached #{count} files."
22
22
  end
23
23
 
24
24
  def read_content(path)
@@ -0,0 +1,175 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'ruby-progressbar'
4
+ require 'tempfile'
5
+ require 'fileutils'
6
+
7
+ module Lydown::CLI::Installer
8
+ class << self
9
+ def install(package, version = nil)
10
+ case package
11
+ when 'lilypond'
12
+ Lilypond.install(version)
13
+ else
14
+ STDERR.puts "Unknown package name specified"
15
+ exit!(1)
16
+ end
17
+ end
18
+ end
19
+
20
+ module Lilypond
21
+ class << self
22
+ LILYPOND_DEFAULT_VERSION = "2.19.29"
23
+
24
+ def detect_version(specified_version)
25
+ case specified_version
26
+ when nil, 'stable'
27
+ list = get_version_list
28
+ end
29
+ end
30
+
31
+ def install(version = nil)
32
+ platform = detect_lilypond_platform
33
+ version ||= LILYPOND_DEFAULT_VERSION
34
+ # version = detect_version(version)
35
+ url = lilypond_install_url(platform, version)
36
+ fn = Tempfile.new('lydown-lilypond-installer').path
37
+
38
+ download_lilypond(url, fn)
39
+ install_lilypond_files(fn, platform, version)
40
+ rescue => e
41
+ STDERR.puts "Failed to install lilypond #{version}"
42
+ puts e.message
43
+ puts e.backtrace.join("\n")
44
+ exit(1)
45
+ end
46
+
47
+ BASE_URL = "http://download.linuxaudio.org/lilypond/binaries"
48
+
49
+ def lilypond_install_url(platform, version)
50
+ ext = platform =~ /darwin/ ? ".tar.bz2" : ".sh"
51
+ filename = "lilypond-#{version}-1.#{platform}"
52
+
53
+ "#{BASE_URL}/#{platform}/#{filename}#{ext}"
54
+ end
55
+
56
+ def detect_lilypond_platform
57
+ case RUBY_PLATFORM
58
+ when /x86_64-darwin/
59
+ "darwin-x86"
60
+ when /ppc-darwin/
61
+ "darwin-ppc"
62
+ when "i686-linux"
63
+ "linux-x86"
64
+ when "x86_64-linux"
65
+ "linux-64"
66
+ when "ppc-linux"
67
+ "linux-ppc"
68
+ end
69
+ end
70
+
71
+ def download_lilypond(url, fn)
72
+ STDERR.puts "Downloading #{url}"
73
+
74
+ url_base = url.split('/')[2]
75
+ url_path = '/'+url.split('/')[3..-1].join('/')
76
+ download_count = 0
77
+
78
+ Net::HTTP.start(url_base) do |http|
79
+ request_url = URI.escape(url_path)
80
+ response = http.request_head(request_url)
81
+ total_size = response['content-length'].to_i
82
+ pbar = ProgressBar.create(title: 'Downloading', total: total_size)
83
+ File.open(fn, 'w') do |f|
84
+ http.get(request_url) do |data|
85
+ f << data
86
+ download_count += data.length
87
+ pbar.progress = download_count if download_count <= total_size
88
+ end
89
+ end
90
+ pbar.finish
91
+ end
92
+ end
93
+
94
+ def install_lilypond_files(fn, platform, version)
95
+ case platform
96
+ when /darwin/
97
+ install_lilypond_files_osx(fn, version)
98
+ when /linux/
99
+ install_lilypond_files_linux(fn, version)
100
+ end
101
+ end
102
+
103
+ def install_lilypond_files_osx(fn, version)
104
+ target = "/tmp/lydown/installer/lilypond"
105
+ FileUtils.mkdir_p(target)
106
+
107
+ STDERR.puts "Extracting..."
108
+ exec "tar -xjf #{fn} -C #{target}"
109
+
110
+ copy_lilypond_files("#{target}/LilyPond.app/Contents/Resources", version)
111
+ end
112
+
113
+ def install_lilypond_files_linux(fn, version)
114
+ target = "/tmp/lydown/installer/lilypond"
115
+ FileUtils.mkdir_p(target)
116
+
117
+ # create temp directory in which to untar file
118
+ tmp_dir = "/tmp/lydown/#{Time.now.to_f}"
119
+ FileUtils.mkdir_p(tmp_dir)
120
+
121
+ FileUtils.cd(tmp_dir) do
122
+ exec "sh #{fn} --tarball"
123
+ end
124
+
125
+ STDERR.puts "Extracting..."
126
+ exec "tar -xjf #{tmp_dir}/#{fn} -C #{target}"
127
+
128
+ copy_lilypond_files_linux("#{target}/usr", version)
129
+ end
130
+
131
+ def copy_lilypond_files(base_path, version)
132
+ target_dir = File.expand_path("~/.lydown/packages/lilypond/#{version}")
133
+
134
+ FileUtils.rm_rf(target_dir) if File.exists?(target_dir)
135
+
136
+ # create directory for lilypond files
137
+ FileUtils.mkdir_p(target_dir)
138
+
139
+ # copy files
140
+ STDERR.puts "Copying..."
141
+ %w{bin etc lib lib64 share var}.each do |entry|
142
+ dir = File.join(base_path, entry)
143
+ FileUtils.cp_r(dir, target_dir, remove_destination: true) if File.directory?(dir)
144
+ end
145
+
146
+ install_lilypond_executable(base_path, version)
147
+ end
148
+
149
+ BIN_SCRIPT_PATH = "#{File.expand_path('~')}/bin/lilypond"
150
+
151
+ def install_lilypond_executable(base_path, version)
152
+ target_dir = File.expand_path("~/.lydown/packages/lilypond/#{version}")
153
+
154
+ script = "#!/bin/sh\n#{target_dir}/bin/lilypond \"$@\"\n"
155
+
156
+ # create executable
157
+ FileUtils.rm(BIN_SCRIPT_PATH) if File.file?(BIN_SCRIPT_PATH)
158
+ File.open(BIN_SCRIPT_PATH, 'w+') {|f| f << script}
159
+ FileUtils.chmod('+x', BIN_SCRIPT_PATH)
160
+ # symlink_path = File.expand_path('~/bin/lilypond')
161
+ # FileUtils.ln_sf("#{target_dir}/bin/lilypond", symlink_path)
162
+
163
+ test_lilypond
164
+ end
165
+
166
+ def test_lilypond
167
+ STDERR.puts `lilypond -v`
168
+ end
169
+
170
+ def exec(cmd)
171
+ raise unless system(cmd)
172
+ end
173
+ end
174
+ end
175
+ end
@@ -3,55 +3,55 @@ require 'directory_watcher'
3
3
  module Lydown::CLI::Proofing
4
4
  class << self
5
5
  def start_proofing(opts)
6
- source = opts[:source_filename]
7
-
8
- Lydown::CLI::Diff.fill_cache(source)
9
-
10
6
  $stderr.puts "Proof mode: #{source} -> #{opts[:output_filename]}"
11
- last_proof_path = nil
12
7
 
13
- watch_directory(source, opts)
14
- end
15
-
16
- def watch_directory(source, opts)
17
- dw = DirectoryWatcher.new(
18
- File.expand_path(source),
19
- glob: ["**/*.ld"],
20
- pre_load: true
21
- )
22
- dw.interval = 0.25
23
-
24
- dw.add_observer do |*args|
25
- args.each do |e|
26
- if e.type == :modified
27
- path = File.expand_path(e.path)
28
- if path =~ /^#{File.expand_path(source)}\/(.+)/
29
- path = $1
30
- end
31
- last_proof_path = e.path unless File.basename(e.path) == 'movement.ld'
32
- if last_proof_path
33
- file_opts = opts.deep_merge opts_for_path(last_proof_path, opts)
34
- file_opts[:base_path] = path
35
- process(file_opts)
36
- end
37
- end
38
- end
39
- end
40
-
41
8
  trap("INT") {return}
42
- dw.start
9
+ watch(opts)
43
10
  loop {sleep 1000}
44
11
  ensure
45
- dw.stop
12
+ unwatch
46
13
  end
47
14
 
48
- def globs(path)
49
- Dir.chdir(path) do
50
- dirs = Dir['*'].select { |x| File.directory?(x) }
15
+ def watch(opts)
16
+ unwatch # teardown previous watcher
17
+
18
+ source = opts[:source_filename]
19
+ Lydown::CLI::Diff.fill_cache(source)
20
+ @last_proof_path = nil
21
+
22
+ @watcher = DirectoryWatcher.new(source, glob: ["**/*.ld"], pre_load: true)
23
+
24
+ @watcher.interval = 0.25
25
+ @watcher.add_observer do |*events|
26
+ events.each do |e|
27
+ handle_changed_file(e, opts) if e.type == :modified
28
+ end
51
29
  end
30
+ @watcher.start
31
+ end
52
32
 
53
- dirs = dirs.map { |x| "#{x}/**/*" }
54
- dirs
33
+ def unwatch
34
+ return unless @watcher
35
+
36
+ @watcher.stop
37
+ @watcher = nil
38
+ end
39
+
40
+ def handle_changed_file(event, opts)
41
+ path = File.expand_path(event.path)
42
+ if path =~ /^#{opts[:source_filename]}\/(.+)/
43
+ path = $1
44
+ end
45
+ @last_proof_path = event.path unless File.basename(event.path) == 'movement.ld'
46
+ if @last_proof_path
47
+ file_opts = opts.deep_merge(opts_for_path(@last_proof_path, opts))
48
+ file_opts[:base_path] = path
49
+ process(file_opts)
50
+ end
51
+ rescue => e
52
+ puts e.class
53
+ puts e.message
54
+ puts e.backtrace.join("\n")
55
55
  end
56
56
 
57
57
  def opts_for_path(path, opts)
@@ -87,7 +87,10 @@ module Lydown::CLI::Proofing
87
87
  def process(opts)
88
88
  if opts[:line_range] != [nil, nil]
89
89
  t = Time.now.strftime("%H:%M:%S")
90
- $stderr.puts "[#{t}] Changed: #{opts[:base_path]} (lines #{opts[:line_range][0]}..#{opts[:line_range][1]})"
90
+ unless opts[:silent]
91
+ $stderr.puts "[#{t}] Changed: #{opts[:base_path]} \
92
+ (lines #{opts[:line_range][0]}..#{opts[:line_range][1]})"
93
+ end
91
94
  Lydown::CLI::Compiler.process(opts)
92
95
  end
93
96
  end