From 320536b7d6bb79250e6fefe48d3a6be8c13008d2 Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu Date: Tue, 30 Dec 2014 21:28:02 +0200 Subject: [PATCH] Add Zeal::Feed for working with documentation feeds --- MANIFEST | 1 + Makefile.PL | 7 +- lib/Zeal/Feed.pm | 178 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 lib/Zeal/Feed.pm diff --git a/MANIFEST b/MANIFEST index c930f3e..4ca629c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -2,6 +2,7 @@ Changes lib/Zeal.pm lib/Zeal/Docset.pm lib/Zeal/Document.pm +lib/Zeal/Feed.pm Makefile.PL MANIFEST README diff --git a/Makefile.PL b/Makefile.PL index 82d68c0..a1ff622 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -10,11 +10,14 @@ WriteMakefile( LICENSE => 'perl', SIGN => 1, PREREQ_PM => { - qw/Class::Accessor::Fast 0 + qw/Archive::Tar 0 + Class::Accessor::Fast 0 DBI 0 DBD::SQLite 0 File::Slurp 0 - Mac::PropertyList::SAX 0/, + File::Which 0 + Mac::PropertyList::SAX 0 + XML::Rules 0/, }, META_ADD => { dynamic_config => 0, diff --git a/lib/Zeal/Feed.pm b/lib/Zeal/Feed.pm new file mode 100644 index 0000000..1b02dfa --- /dev/null +++ b/lib/Zeal/Feed.pm @@ -0,0 +1,178 @@ +package Zeal::Feed; + +use 5.014000; +use strict; +use warnings; +use re '/s'; + +our $VERSION = '0.000_001'; + +use parent qw/Class::Accessor::Fast/; +__PACKAGE__->mk_ro_accessors(qw/version/); + +use Cwd qw/getcwd/; +use File::Spec::Functions qw/catfile rel2abs/; +use HTTP::Tiny; + +use Archive::Tar; +use File::Slurp qw/read_file/; +use File::Which; +use XML::Rules; + +sub new { + my ($class, $url) = @_; + $class->new_from_content(HTTP::Tiny->new->get($url)->{content}); +} + +sub new_from_file { + my ($class, $file) = @_; + $class->new_from_content(scalar read_file $file); +} + +sub new_from_content { + my ($class, $xml) = @_; + my ($version, @urls) = @_; + + my $self = XML::Rules->parse( + rules => { + _default => 'content', + entry => 'pass', + url => 'content array', + 'other-versions' => undef, + }, + stripspaces => 3|4, + )->($xml); + bless $self, $class +} + +sub urls { + my ($self) = @_; + @{$self->{url}} +} + +sub url { + my ($self) = @_; + my @urls = $self->urls; + $urls[int rand @urls] +} + +sub _unpack_tar_to_dir { + my ($file, $dir) = @_; + my $tar = which 'tar' or which 'gtar'; + if ($tar && !$ENV{ZEAL_USE_INTERNAL_TAR}) { + my $arg = '-xf'; + $arg = '-xzf' if $file =~ /[.]t?gz$/; + $arg = '-xjf' if $file =~ /[.]bz2$/; + system $tar, -C => $dir, $arg => $file + } else { + $file = rel2abs $file; + my $oldwd = getcwd; + chdir $dir; + Archive::Tar->extract_archive($file); + chdir $oldwd; + } +} + +sub download { + my ($self, $path) = @_; + my ($name) = $self->url =~ /([^\/])+$/; + my $file = catfile $path, $name; + HTTP::Tiny->new->mirror($self->url, $file); + _unpack_tar_to_dir $file, $path; + unlink $file; +} + +1; +__END__ + +=encoding utf-8 + +=head1 NAME + +Zeal::Feed - Class representing a Dash/Zeal documentation feed + +=head1 SYNOPSIS + + use Zeal::Feed; + my $feed = Zeal::Feed->new('http://example.com/feed.xml'); + say $feed->version; # 12.2.3 + say $feed->url; # http://another.example.com/file.tar.gz + + # Download to /home/mgv/docsets/file.docset + $feed->download('/home/mgv/docsets/'); + +=head1 DESCRIPTION + +Dash is an offline API documentation browser. Zeal::Feed is a class +representing a Dash/Zeal documentation feed. + +A documentation feed is an XML file describing a docset. It contains +the version of the docset and one or more URLs to a (typically +.tar.gz) archive of the docset. + +Available methods: + +=over + +=item Zeal::Feed->B(I<$url>) + +Create a Zeal::Feed object from an HTTP URL. + +=item Zeal::Feed->B(I<$file>) + +Create a Zeal::Feed object from a file. + +=item Zeal::Feed->B(I<$xml>) + +Create a Zeal::Feed object from a string. + +=item $feed->B + +The version of this feed. + +=item $feed->B + +A list of URLs to this docset. + +=item $feed->B + +An URL to this docset, randomly chosen from the list returned by B. + +=item $feed->B(I<$path>) + +Download and unpack the docset inside the I<$path> directory. + +Uses the F binary for unpacking if availablem, L +otherwise. You can set the ZEAL_USE_INTERNAL_TAR environment variable +to a true value to force the use of L. + +=back + +=head1 ENVIRONMENT + +=over + +=item ZEAL_USE_INTERNAL_TAR + +If true, B will always use L. + +=back + +=head1 SEE ALSO + +L, L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2014 by Marius Gavrilescu + +This library is free software; you can redistribute it and/or modify +it under the same terms as Perl itself, either Perl version 5.20.1 or, +at your option, any later version of Perl 5 you may have available. + + +=cut -- 2.30.2