UPDATE July 24, 2010: This post is now totally obsolete. See this post instead.
This is an update to my previous post. Now, Autolily’s single argument is no longer required to be the bare *.ly filename itself, but instead may optionally include a path! See the embedded comments in the source code below. Enjoy!
1 #!/usr/bin/ruby
2 #===============================================================================================================#
3 # Program name: Autolily #
4 # LICENSE: PUBLIC DOMAIN #
5 # This program takes 1 argument, the name of a lilypond file (*.ly), and watches it for changes every 1 second. #
6 # If there has been any change, it simply calls lilypond on it to create a new .pdf/.ps/.midi of it. #
7 # #
8 # Place this script somewhere, like in ~/scripts #
9 # Then, open up a terminal and call it like so: ~/scripts/autolily.rb [file] #
10 # [file] must be a LilyPond file (.ly), but it can be located anywhere -- i.e., you may include paths in your #
11 # file, such as "~/sheet-music/classical/bach2.ly" or "../../bach3.ly". #
12 # #
13 # You might want to do a "sudo ln -s" of autolily.rb to one of your system's $PATH directories (e.g., /usr/bin) #
14 # to avoid typing out the path to autolily.rb every time you use it. Continuing the example from above, #
15 # something like "sudo ln -s ~/scripts/autolily.rb /usr/bin/autolily" should do (make sure that #
16 # /usr/bin/autolily does not exist already, as the above comman will overwrite that file if it exists). #
17 # #
18 # Now you can just do: #
19 # #
20 # autolily [file] #
21 # #
22 # from anywhere in your system! #
23 # #
24 # To exit, press CTRL-C. #
25 #===============================================================================================================#
26
27 if ARGV.size > 0
28 file_data_orig = ""
29 file = ARGV.shift
30 pathsize = file.split("/").size
31 ls_call = "ls --full-time"
32
33 # make sure that the "file" variable is a filename, and not mixed with its path
34 if pathsize > 1
35 path_to_file = file.split("/").first(pathsize - 1).join("/")
36 file = file.split("/").last
37 ls_call << " #{path_to_file}" # modify our `ls` command to reflect relative location of file
38 end
39
40 `#{ls_call}`.split("\n").each do |line|
41 if line.split(/\s/).last == file
42 file_data_orig = line
43 break
44 end
45 end
46 file_data_new = ""
47
48 # enter infinite loop -- keep compiling the given lilypond file if it has changed in the past 1 second
49 while true
50 # detect the file size and also timestamp
51 lsarr = `#{ls_call}`.split("\n")
52 lsarr.shift # get rid of the first line, since that is the size of all the files in the directory
53
54 # find our file from ls's output!
55 lsarr.each do |line|
56 if line.split(/\s/).last == file
57 file_data_new = line
58 break
59 end
60 end
61
62 # if there is any change detected, run lilypond on it
63 if file_data_orig != file_data_new
64 puts "\n\e[1;4;38;5;226mAutolily: Change detected in given file; invoking lilypond...\e[0m\n"
65 if pathsize > 1
66 `lilypond "#{path_to_file}/#{file}"`
67 else
68 `lilypond "#{file}"`
69 end
70 file_data_orig = file_data_new
71 end
72 sleep 1
73 end
74 else
75 puts "No .ly file specified.\n"
76 end