| File: | lib/Makefile/Update.pm |
| Coverage: | 90.0% |
| line | stmt | bran | cond | sub | code |
|---|---|---|---|---|---|
| 1 | package Makefile::Update; | ||||
| 2 | |||||
| 3 | # ABSTRACT: Update make files. | ||||
| 4 | |||||
| 5 | 23 23 23 | use strict; | |||
| 6 | 23 23 23 | use warnings; | |||
| 7 | 23 23 23 | use autodie; | |||
| 8 | |||||
| 9 | 23 23 23 | use Exporter qw(import); | |||
| 10 | |||||
| 11 | our @EXPORT = qw(read_files_list upmake); | ||||
| 12 | |||||
| 13 | # VERSION | ||||
| 14 | |||||
| 15 - 21 | =head1 SYNOPSIS
use Makefile::Update;
my $vars = read_files_list('files.lst');
upmake('foo.vcxproj', $vars->{sources}, $vars->{headers});
=cut | ||||
| 22 | |||||
| 23 | =func read_files_list | ||||
| 24 | |||||
| 25 | Reads the file containing the file lists definitions and returns a hash ref | ||||
| 26 | with variable names as keys and refs to arrays of the file names as values. | ||||
| 27 | |||||
| 28 | Takes an (open) file handle as argument. | ||||
| 29 | |||||
| 30 | The file contents is supposed to have the following very simple format: | ||||
| 31 | |||||
| 32 | # Comments are allowed and ignored. | ||||
| 33 | # | ||||
| 34 | # The variable definitions must always be in the format shown below, | ||||
| 35 | # i.e. whitespace is significant and there should always be a single | ||||
| 36 | # file per line. | ||||
| 37 | sources = | ||||
| 38 | file1.cpp | ||||
| 39 | file2.cpp | ||||
| 40 | |||||
| 41 | headers = | ||||
| 42 | file1.h | ||||
| 43 | file2.h | ||||
| 44 | |||||
| 45 | # It is also possible to define variables in terms of other variables | ||||
| 46 | # defined before it in the file (no forward references): | ||||
| 47 | everything = | ||||
| 48 | $sources | ||||
| 49 | $headers | ||||
| 50 | =cut | ||||
| 51 | |||||
| 52 | sub read_files_list | ||||
| 53 | { | ||||
| 54 | 3 | my ($fh) = @_; | |||
| 55 | |||||
| 56 | 3 | my ($var, %vars); | |||
| 57 | 3 | while (<$fh>) { | |||
| 58 | 42 | chomp; | |||
| 59 | 42 | s/#.*$//; | |||
| 60 | 42 | s/^\s+//; | |||
| 61 | 42 | s/\s+$//; | |||
| 62 | 42 | next if !$_; | |||
| 63 | |||||
| 64 | 27 | if (/^(\w+)\s*=$/) { | |||
| 65 | 9 | $var = $1; | |||
| 66 | } else { | ||||
| 67 | 18 | die "Unexpected contents outside variable definition at line $.\n" | |||
| 68 | unless defined $var; | ||||
| 69 | 18 | if (/^\$(\w+)$/) { | |||
| 70 | 6 | my $name = $1; | |||
| 71 | die qq{Reference to undefined variable "$name" in the } . | ||||
| 72 | qq{assignment to "$var" at line $.\n} | ||||
| 73 | 6 | unless exists $vars{$name}; | |||
| 74 | 6 | my $value = $vars{$name}; | |||
| 75 | 6 12 | push @{$vars{$var}}, $_ for @$value; | |||
| 76 | } else { | ||||
| 77 | 12 12 | push @{$vars{$var}}, $_; | |||
| 78 | } | ||||
| 79 | } | ||||
| 80 | } | ||||
| 81 | |||||
| 82 | 3 | return \%vars; | |||
| 83 | } | ||||
| 84 | |||||
| 85 | =func upmake | ||||
| 86 | |||||
| 87 | Update a file in place using the specified function and passing it the rest of | ||||
| 88 | the arguments. | ||||
| 89 | |||||
| 90 | The first parameter is either just the file path or a hash reference which may | ||||
| 91 | contain the following keys: | ||||
| 92 | |||||
| 93 - 119 | =over =item C<file> The path to the file to be updated, required. =item C<verbose> If true, give more messages about what is being done. =item C<quiet> If true, don't output any non-error messages. =item C<dryrun> If true, don't really update the file but just output whether it would have been updated or not. If C<verbose> is also true, also output the diff of the changes that would have been done. =back This is meant to be used with C<update_xxx()> defined in different Makefile::Update::Xxx modules. Returns 1 if the file was changed or 0 otherwise. =cut | ||||
| 120 | |||||
| 121 | sub upmake | ||||
| 122 | { | ||||
| 123 | 31 | my $file_or_options = shift; | |||
| 124 | 31 | my ($updater, @args) = @_; | |||
| 125 | |||||
| 126 | 31 | my ($fname, $verbose, $quiet, $dryrun); | |||
| 127 | 31 | if (ref $file_or_options eq 'HASH') { | |||
| 128 | 25 | $fname = $file_or_options->{file}; | |||
| 129 | 25 | $verbose = $file_or_options->{verbose}; | |||
| 130 | 25 | $quiet = $file_or_options->{quiet}; | |||
| 131 | 25 | $dryrun = $file_or_options->{dryrun}; | |||
| 132 | } else { | ||||
| 133 | 6 | $fname = $file_or_options; | |||
| 134 | 6 | $verbose = | |||
| 135 | $quiet = | ||||
| 136 | $dryrun = 0; | ||||
| 137 | } | ||||
| 138 | |||||
| 139 | 31 | if ($dryrun) { | |||
| 140 | 6 | my $old = do { | |||
| 141 | 6 | local $/; | |||
| 142 | 6 | open my $f, '<', $fname; | |||
| 143 | <$f> | ||||
| 144 | 6 | }; | |||
| 145 | 6 | my $new = ''; | |||
| 146 | |||||
| 147 | 6 | open my $in, '<', \$old; | |||
| 148 | 6 | open my $out, '>', \$new; | |||
| 149 | |||||
| 150 | 6 | if ($updater->($in, $out, @args)) { | |||
| 151 | 3 | print qq{Would update "$fname"}; | |||
| 152 | |||||
| 153 | 3 | if ($verbose) { | |||
| 154 | 0 0 | if (eval { require Text::Diff; }) { | |||
| 155 | 0 | print " with the following changes:\n"; | |||
| 156 | |||||
| 157 | 0 | print Text::Diff::diff(\$old, \$new, { | |||
| 158 | FILENAME_A => $fname, | ||||
| 159 | FILENAME_B => "$fname.new" | ||||
| 160 | }); | ||||
| 161 | } else { | ||||
| 162 | 0 | print ".\n"; | |||
| 163 | |||||
| 164 | 0 | warn qq{Can't display diff of the changes, please install Text::Diff module.\n}; | |||
| 165 | } | ||||
| 166 | } else { | ||||
| 167 | 3 | print ".\n"; | |||
| 168 | } | ||||
| 169 | } else { | ||||
| 170 | 3 | print qq{Wouldn't change the file "$fname".\n}; | |||
| 171 | } | ||||
| 172 | |||||
| 173 | 6 | return 0; | |||
| 174 | } | ||||
| 175 | |||||
| 176 | 25 | my $fname_new = "$fname.upmake.new"; # TODO make it more unique | |||
| 177 | |||||
| 178 | 25 | open my $in, '<', $fname; | |||
| 179 | 25 | open my $out, '>', $fname_new; | |||
| 180 | |||||
| 181 | 25 | my $changed = $updater->($in, $out, @args); | |||
| 182 | |||||
| 183 | 25 | close $in; | |||
| 184 | 25 | close $out; | |||
| 185 | |||||
| 186 | 25 | if ($changed) { | |||
| 187 | 14 | rename $fname_new, $fname; | |||
| 188 | } else { | ||||
| 189 | 11 | unlink $fname_new; | |||
| 190 | } | ||||
| 191 | |||||
| 192 | 25 | if ($changed) { | |||
| 193 | 14 | print qq{File "$fname" successfully updated.\n} unless $quiet; | |||
| 194 | 14 | return 1; | |||
| 195 | } else { | ||||
| 196 | 11 | print qq{No changes in the file "$fname".\n} if $verbose; | |||
| 197 | 11 | return 0; | |||
| 198 | } | ||||
| 199 | } | ||||
| 200 | |||||
| 201 | 1; | ||||