lydown 0.10.0 → 0.12.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +452 -206
- data/bin/lydown +5 -1
- data/lib/lydown/cache.rb +1 -2
- data/lib/lydown/cli.rb +2 -0
- data/lib/lydown/cli/commands.rb +25 -7
- data/lib/lydown/cli/compiler.rb +32 -9
- data/lib/lydown/cli/diff.rb +1 -1
- data/lib/lydown/cli/installer.rb +175 -0
- data/lib/lydown/cli/proofing.rb +44 -41
- data/lib/lydown/cli/repl.rb +232 -0
- data/lib/lydown/cli/support.rb +33 -0
- data/lib/lydown/core_ext.rb +8 -0
- data/lib/lydown/lilypond.rb +1 -0
- data/lib/lydown/ly_lib/lib.ly +1 -1
- data/lib/lydown/parsing.rb +1 -1
- data/lib/lydown/rendering.rb +34 -0
- data/lib/lydown/rendering/base.rb +1 -1
- data/lib/lydown/rendering/movement.rb +0 -11
- data/lib/lydown/rendering/music.rb +2 -0
- data/lib/lydown/rendering/notes.rb +2 -0
- data/lib/lydown/rendering/settings.rb +34 -8
- data/lib/lydown/rendering/source_ref.rb +3 -2
- data/lib/lydown/templates/lilypond_doc.erb +5 -0
- data/lib/lydown/templates/movement.erb +1 -1
- data/lib/lydown/templates/variables.erb +5 -0
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +9 -4
- data/lib/lydown/work_context.rb +6 -8
- metadata +7 -33
data/bin/lydown
CHANGED
data/lib/lydown/cache.rb
CHANGED
@@ -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.
|
28
|
+
Digest::MD5.hexdigest(p.is_a?(String) ? p : p.to_s)
|
30
29
|
end.join('-')
|
31
30
|
end
|
32
31
|
|
data/lib/lydown/cli.rb
CHANGED
data/lib/lydown/cli/commands.rb
CHANGED
@@ -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
|
-
|
10
|
-
|
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] =
|
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)
|
data/lib/lydown/cli/compiler.rb
CHANGED
@@ -18,16 +18,26 @@ module Lydown::CLI::Compiler
|
|
18
18
|
}
|
19
19
|
|
20
20
|
def process(opts)
|
21
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
237
|
-
|
238
|
-
|
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
|
data/lib/lydown/cli/diff.rb
CHANGED
@@ -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
|
data/lib/lydown/cli/proofing.rb
CHANGED
@@ -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
|
-
|
9
|
+
watch(opts)
|
43
10
|
loop {sleep 1000}
|
44
11
|
ensure
|
45
|
-
|
12
|
+
unwatch
|
46
13
|
end
|
47
14
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
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
|
-
|
54
|
-
|
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
|
-
|
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
|