Almost-minimal filesystem based blog.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
2.7 KiB

v6.0.0: expand EntryStore, test more, cache harder This commit is something of a hairball, the result of evenings-and-weekends hacking building up a set of changes that got out of hand in parallel. If I had the energy to spare, I would break it apart into semantically-related changes, but I don't - and I suppose all this crap being rolled together is at least reflective of how the code was written. These changes are really half-finished, at best. Eventual goals: - App::WRT shouldn't directly touch the filesystem - App::WRT::EntryStore should model the entry archive completely - App::WRT::Renderer should say what to write to the publication directory - This one's a maybe: Filesystem interaction should pass through App::WRT::FileIO or something like it so that EntryStore and Renderer can be more usefully tested, with mocked writes (maybe) I do think this represents an inflection point in the long, silly life of this program: It includes a handful of new tests, and a number of the code changes were in turn easy to make because the test suite begins to model the code in a useful way. It's less and less necessary to run wrt against the p1k3.com archives to be sure that I haven't trashed something. Breaking changes to note: - Will no longer render HTML for nonexistent entries - Months and years which are flatfiles or contain an index are handled differently, albeit less brokenly - EntryStore includes index files in its overall list of entries (this seems to break less than I thought), which trickles out to bin/wrt-ls Overall changes herein: - App::WRT::Date - Move month_name() in here from App::WRT, add tests. - App::WRT::EntryStore - Hash file types for entries (directory or flatfile) - Use keys of file type hash for complete list of entries. - has_prop($entry, $property) - is_dir($entry), is_file($entry), is_extant($entry) - parent_of($entry) - has_index($entry) - Make EntryStore cache whether a file is a flatfile or a directory, as well as its existence, in a single hash. - Include index flatfiles in @source_files for use by has_index() - Various tests. - App::WRT::FileIO - Still duplicates a bunch of shit from Util, so that needs sorted. - App::WRT::Renderer - Convert to a proper class. - Add experimental FileIO class to use in Renderer (imperfect, tricky, still thinking about this). The idea is to separate out the concerns of reading and writing the filesystem. - App::WRT - Refactor display() and improve tests - Use "@entries" instead of "@options" for clarity - Handle entry names that might evaluate as false - Test running display() without any params - Rename expand_option() -> expand_alias(), refactor - Use EntryStore::has_prop() to detect wrt-noexpand.prop - year(), month(), entry() partially rewritten to use EntryStore - year() should handle months which are a flatfile - Refactor icon_markup() to use is_file() / is_dir() / is_extant(), add tests. - Add subtitle to feeds - bin/wrt-ls is now a "modulino" with tests - bin/display errors on non-existent entries - Build.PL - Remove bogus XML::Feed dependency
5 years ago
  1. package App::WRT::FileIO;
  2. use strict;
  3. use warnings;
  4. use Carp;
  5. use Encode;
  6. use File::Copy;
  7. use File::Path qw(make_path);
  8. use Data::Dumper;
  9. =pod
  10. =head1 NAME
  11. App::WRT::FileIO - read and write directories and files
  12. =head1 SYNOPSIS
  13. use App::WRT::FileIO;
  14. my $io = App::WRT::FileIO->new();
  15. =head1 METHODS
  16. =over
  17. =item new($class)
  18. Get a new FileIO object.
  19. =cut
  20. sub new {
  21. my $class = shift;
  22. my %params = (
  23. last_error => '',
  24. );
  25. my $self = \%params;
  26. bless $self, $class;
  27. }
  28. =item dir_list($dir, $sort_order, $pattern)
  29. Return a $sort_order sorted list of files matching regex $pattern in a
  30. directory.
  31. Calls $sort_order, which can be one of:
  32. alpha - alphabetical
  33. reverse_alpha - alphabetical, reversed
  34. high_to_low - numeric, high to low
  35. low_to_high - numeric, low to high
  36. =cut
  37. sub dir_list {
  38. my ($self, $dir, $sort_order, $pattern) = @_;
  39. $pattern ||= qr/^[0-9]{1,2}$/;
  40. $sort_order ||= 'high_to_low';
  41. opendir my $list_dir, $dir
  42. or die "Couldn't open $dir: $!";
  43. my @files = sort $sort_order
  44. grep { m/$pattern/ }
  45. readdir $list_dir;
  46. closedir $list_dir;
  47. return @files;
  48. }
  49. # Various named sorts for dir_list:
  50. sub alpha { $a cmp $b; } # alphabetical
  51. sub high_to_low { $b <=> $a; } # numeric, high to low
  52. sub low_to_high { $a <=> $b; } # numberic, low to high
  53. sub reverse_alpha { $b cmp $a; } # alphabetical, reversed
  54. =item file_put_contents($file, $contents)
  55. Write $contents string to $file path. Because:
  56. L<https://secure.php.net/manual/en/function.file-put-contents.php>
  57. =cut
  58. sub file_put_contents {
  59. my ($self, $file, $contents) = @_;
  60. open(my $fh, '>', $file)
  61. or die "Unable to open $file for writing: $!";
  62. print $fh $contents;
  63. close $fh;
  64. }
  65. =item file_get_contents($file)
  66. Get contents string of $file path. Because:
  67. L<https://secure.php.net/manual/en/function.file-get-contents.php>
  68. =cut
  69. sub file_get_contents {
  70. my ($self, $file) = @_;
  71. open my $fh, '<', $file
  72. or croak "Couldn't open $file: $!\n";
  73. my $contents;
  74. {
  75. # line separator:
  76. local $/ = undef;
  77. $contents = <$fh>;
  78. }
  79. close $fh or croak "Couldn't close $file: $!";
  80. # TODO: _May_ want to assume here that any file is UTF-8 text.
  81. # http://perldoc.perl.org/perlunitut.html
  82. # return decode('UTF-8', $contents);
  83. return $contents;
  84. }
  85. =item file_copy($source, $dest)
  86. =cut
  87. sub file_copy {
  88. my ($self, $source, $dest) = @_;
  89. copy($source, $dest);
  90. }
  91. =item dir_make($source, $dest)
  92. =cut
  93. sub dir_make {
  94. my ($self, $path) = @_;
  95. my $path_err;
  96. make_path($path, { error => \$path_err });
  97. if (@{ $path_err }) {
  98. $self->{last_error} = Dumper($path_err);
  99. return 0;
  100. }
  101. return 1;
  102. }
  103. =back
  104. =cut
  105. 1;