lydown 0.10.0 → 0.12.4
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 +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
|