App-Followme

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

App::Followme::Guide - How to install, configure, and run followme

# SYNOPSIS

    followme [directory]

# DESCRIPTION

Updates a static website after changes. Constant portions of each page are
updated to match, text files are converted to html, indexes are created
for files in the archive, and changed files are uploaded to the remote server.

The followme script is run on the directory or file passed as its argument. If
no argument is given, it is run on the current directory.

If a file is passed, the script is run on the directory the file is in. In
addition, the script is run in quick mode, meaning that only the directory
the file is in is checked for changes. Otherwise, not only that directory, but
all directories below it are checked.

# CHANGES

README.md  view on Meta::CPAN

    be used if you also want an rss file.

- [App::Followme::CreateSitemap](https://metacpan.org/pod/App%3A%3AFollowme%3A%3ACreateSitemap)

    This module creates a sitemap file, which is a text file containing the url of
    every page on the site, one per line. It is also intended as a simple example of
    how to write a module that can be run by followme.

- [App::Followme::UploadSite](https://metacpan.org/pod/App%3A%3AFollowme%3A%3AUploadSite)

    This module uploads changed files to a remote site. The default method to do the
    uploads is local copy, but that can be changed by changing the parameter upload\_pkg.
    This package computes a checksum for every file in the site. If the checksum has
    changed since the last time it was run, the file is uploaded to the remote site.
    If there is a checksum, but no local file, the file is deleted from the remote
    site. If followme is run in quick mode, only files whose modification date is
    later then the last time it was run are checked.

# RUNNING

The followme script is run on the directory or file passed as its argument. If
no argument is given, it is run on the current directory. If a file is passed,
the script is run on the directory the file is in and followme is run in
quick mode. Quick mode is an implicit promise that only the named file has

lib/App/Followme/Guide.pm  view on Meta::CPAN

App::Followme::Guide - How to install, configure, and run followme

=head1 SYNOPSIS

    followme [directory]

=head1 DESCRIPTION

Updates a static website after changes. Constant portions of each page are
updated to match, text files are converted to html, indexes are created
for files in the archive, and changed files are uploaded to the remote server.

The followme script is run on the directory or file passed as its argument. If
no argument is given, it is run on the current directory.

If a file is passed, the script is run on the directory the file is in. In
addition, the script is run in quick mode, meaning that only the directory
the file is in is checked for changes. Otherwise, not only that directory, but
all directories below it are checked.

=head1 CHANGES

lib/App/Followme/Guide.pm  view on Meta::CPAN

be used if you also want an rss file.

=item L<App::Followme::CreateSitemap>

This module creates a sitemap file, which is a text file containing the url of
every page on the site, one per line. It is also intended as a simple example of
how to write a module that can be run by followme.

=item L<App::Followme::UploadSite>

This module uploads changed files to a remote site. The default method to do the
uploads is local copy, but that can be changed by changing the parameter upload_pkg.
This package computes a checksum for every file in the site. If the checksum has
changed since the last time it was run, the file is uploaded to the remote site.
If there is a checksum, but no local file, the file is deleted from the remote
site. If followme is run in quick mode, only files whose modification date is
later then the last time it was run are checked.

=back

=head1 RUNNING

The followme script is run on the directory or file passed as its argument. If
no argument is given, it is run on the current directory. If a file is passed,

lib/App/Followme/UploadData.pm  view on Meta::CPAN


=head1 SYNOPSIS

    use App::Followme::UploadData;
    my $meta = App::Followme::UploadData->new(exclude => '*.cfg');
    my $index_file = $self->to_file($self->{base_directory});
    my $files = App::Followme::Template->build('files', $index_file);

=head1 DESCRIPTION

This module generates the list of files and folders to be uploaded to the
remote site and the checksums for each file.

=head1 METHODS

All data classes are first instantiated by calling new and data items are
retrieved by calling the build method with the item name as the first argument
and the file or folder as the second argument.

=head1 VARIABLES

The file metadata class can evaluate the following variables. When passing
a name to the build method, the sigil should not be used.

=over 4

=item @files

The list of files to be uploaded from a folder.

=item @folders

The list of folders contining files to be uploaded

=item $checksum

The MD5 hash of the file contents, used for determining if file has changed
and needs to be uploaded.

=back

=head1 CONFIGURATION

This class has the following configuration variables:

=over 4

=item excluded

A filename pattern or comma separated list of filename patterns that match files
that should not be uploaded. The default value is '*.cfg' which matches
configuration files.

=item exclude_dirs

A filename pattern or comma separated list of filename patterns that match
folders that should not be uploaded/ The default value is '.*,_*' which
matches folders starting with a dot (hiddern folders) and starting with an
underscore character.

=back

=head1 LICENSE

Copyright (C) Bernie Simon.

This library is free software; you can redistribute it and/or modify

lib/App/Followme/UploadFtp.pm  view on Meta::CPAN

    my ($self, $local_filename, $remote_filename) = @_;

    my $status;
    $remote_filename = $self->remote_name($remote_filename);

    # Delete file if already there
    if ($self->{ftp}->mdtm($remote_filename)) {
        $self->{ftp}->delete($remote_filename);
    }

    # Change upload mode if necessary
    if (-B $local_filename) {
        if ($self->{ascii}) {
            $self->{ftp}->binary();
            $self->{ascii} = 0;
        }

    } elsif (! $self->{ascii}) {
        $self->{ftp}->ascii();
        $self->{ascii} = 1;
    }

lib/App/Followme/UploadFtp.pm  view on Meta::CPAN

    my $ftp = App::Followme::UploadNone->new(\%configuration);
    $ftp->open($user, $password);
    $ftp->add_directory($dir);
    $ftp->add_file($local_filename, $remote_filename);
    $ftp->delete_file($filename);
    $ftp->delete_dir($dir);
    $ftp->close();

=head1 DESCRIPTION

L<App::Followme::UploadSite> splits off methods that do the actual uploading
into a separate package, so it can support more than one method. This package
uploads files using good old ftp.

=head1 METHODS

The following are the public methods of the interface

=over 4

=item $flag = $self->add_directory($dir);

Create a new directory.

lib/App/Followme/UploadFtp.pm  view on Meta::CPAN

=head1 CONFIGURATION

The follow parameters are used from the configuration. In addition, the package
will prompt for and save the user name and password.

=over 4

=item ftp_debug

Set to one to trace the ftp commands issued. Useful to diagnose problems
with ftp uploads. The default value is zero.

=item remote_directory

The top directory of the remote site

=item ftp_url

The url of the remote ftp site.

=item remote_pkg

lib/App/Followme/UploadLocal.pm  view on Meta::CPAN

1;
__END__
=encoding utf-8

=head1 NAME

App::Followme::UploadLocal - Upload files through file copy

=head1 SYNOPSIS

    my $uploader = App::Followme::UploadLocal->new(\%configuration);
    $uploader->open();
    $uploader->add_directory($dir);
    $uploader->add_file($filename);
    $uploader->delete_directory($dir);
    $uploader->delete_file($filename);
    $uploader->close();

=head1 DESCRIPTION

L<App::Followme::UploadSite> splits off methods that do the actual uploading
into a separate package, so it can support more than one method. This package
uploads files to the server using a simple file copy.

=head1 METHODS

The following are the public methods of the interface. The return value
indicates if the operation was successful.

=over 4

=item $flag = $self->add_directory($dir);

lib/App/Followme/UploadNone.pm  view on Meta::CPAN

    my ($self, $user, $password) = @_;
    return;
}

1;
__END__
=encoding utf-8

=head1 NAME

App::Followme::UploadNone - Go through the motions of uploading files

=head1 SYNOPSIS

    my $uploader = App::Followme::UploadNone->new(\%configuration);
    $uploader->open($user, $password);
    $uploader->add_directory($dir);
    $uploader->add_file($local_filename, $remote_filename);
    $uploader->delete_directory($dir);
    $uploader->delete_file($filename);
    $uploader->close();

=head1 DESCRIPTION

L<App::Followme::UploadSite> splits off methods that do the actual uploading
into a separate package, so it can support more than one method. This is the
null method, that does no upload, which is invoked when the user only wants to
update the checksums without doing any uploads. In addition, this package
serves as a template for other packages, because it has all the necessary
methods with the correct interfaces.

=head1 METHODS

The following are the public methods of the interface. The return value
indicates if the operation was successful.

=over 4

lib/App/Followme/UploadSite.pm  view on Meta::CPAN

#----------------------------------------------------------------------
# Read the default parameter values

sub parameters {
    my ($pkg) = @_;

    return (
            verbose => 0,
            max_errors => 5,
            remote_url => '',
            hash_file => 'upload.hash',
            credentials => 'upload.cred',
            state_directory => '_state',
            data_pkg => 'App::Followme::UploadData',
            upload_pkg => 'App::Followme::UploadFtp',
           );
}

#----------------------------------------------------------------------
# Upload changed files in a directory tree

sub run {
    my ($self, $folder) = @_;

    my ($hash, $local) = $self->get_state();

    my ($user, $pass) = $self->get_word();
    $self->{upload}->open($user, $pass);

    eval {
        chdir($self->{top_directory})
            or die "Can't cd to $self->{top_directory}";

        $self->update_folder($self->{top_directory}, $hash, $local);
        $self->clean_files($hash, $local);
        $self->{upload}->close();

        chdir($folder);
    };

    my $error = $@;
    $self->write_hash_file($hash);

    die $error if $error;
    return;
}

lib/App/Followme/UploadSite.pm  view on Meta::CPAN

sub clean_files {
    my ($self, $hash, $local) = @_;

    # Sort files so that files in directories are deleted before
    # their directories are
    my @filenames = sort {length($b) <=> length($a)} keys(%$local);

    foreach my $filename (@filenames) {
        my $flag;
        if ($hash->{$filename} eq 'dir') {
            $flag = $self->{upload}->delete_directory($filename);
        } else {
            $flag = $self->{upload}->delete_file($filename);
        }

        if ($flag) {
            delete $hash->{$filename};
            print "delete $filename\n" if $self->{verbose};

        } else {
            die "Too many upload errors\n" if $self->{max_errors} == 0;
            $self->{max_errors} --;
        }
    }

    return;
}

#----------------------------------------------------------------------
# Get the state of the site, contained in the hash file

lib/App/Followme/UploadSite.pm  view on Meta::CPAN

            my $page = fio_read_page($file);

            if ($page) {
                $page = $self->rewrite_base_tag($page);
                $local_file = rel2abs(catfile($self->{state_directory}, $basename));
                fio_write_page($local_file, $page);
            }
        }
    }

    # Upload the file and return the status of the upload

    my $status = 0;
    my $remote_file = abs2rel($file, $self->{top_directory});
    if ($self->{upload}->add_file($local_file, $remote_file)) {
        $status = 1;

    } else {
        die "Too many upload errors\n" if $self->{max_errors} == 0;
        $self->{max_errors} --;
    }

    # Remove any temporary file
    unlink($local_file) if $file ne $local_file;
    return $status;
}

#----------------------------------------------------------------------
# Update files in one folder

lib/App/Followme/UploadSite.pm  view on Meta::CPAN


    # Check if folder is new

    if ($folder ne $self->{top_directory}) {
        $folder = abs2rel($folder, $self->{top_directory});
        delete $local->{$folder} if exists $local->{$folder};

        if (! exists $hash->{$folder} ||
            $hash->{$folder} ne 'dir') {

            if ($self->{upload}->add_directory($folder)) {
                $hash->{$folder} = 'dir';
                print "add $folder\n" if $self->{verbose};

            } else {
                die "Too many upload errors\n" if $self->{max_errors} == 0;
                $self->{max_errors} --;
            }
        }
    }

    # Check each of the files in the directory

    my $files = $self->{data}->build('files', $index_file);

    foreach my $filename (@$files) {

lib/App/Followme/UploadSite.pm  view on Meta::CPAN


App::Followme::UploadSite - Upload changed and new files

=head1 SYNOPSIS

    my $app = App::Followme::UploadSite->new(\%configuration);
    $app->run($folder);

=head1 DESCRIPTION

This module uploads changed files to a remote site. The default method to do the
uploads is ftp, but that can be changed by changing the parameter upload_pkg.
This package computes a checksum for every file in the site. If the checksum has
changed since the last time it was run, the file is uploaded to the remote site.
If there is a checksum, but no local file, the file is deleted from the remote
site. If this module is run in quick mode, only files whose modification date is
later then the last time it was run are checked.

=head1 CONFIGURATION

The following fields in the configuration file are used:

=over 4

=item credentials

The name of the file which holds the user name and password for the remote site
in obfuscated form. Te default name is 'upload.cred'.

=item hash_file

The name of the file containing all the checksums for files on the site. The
default name is 'upload.hash'.

=item max_errors

The number of upload errors the module tolerate before quitting. The default
value is 5.

=item remote_url

The url of the remote website, e.g. http://www.cloudhost.com.

=item state_directory

The name of the directory containing the credentials and hash file. This
directory name is relative to the top directory of the site. The default
name is '_state'.

=item upload_pkg

The name of the package with methods that add and delete files on the remote
site. The default is L<App::Followme::UploadFtp>. Other packages can be
written, the methods a package must support can be found in
L<App::Followme::UploadNone>.

=item verbose

Print names of uploaded files when not in quick mode

=back

=head1 LICENSE

Copyright (C) Bernie Simon.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

t/UploadSite.t  view on Meta::CPAN

  
mkdir $state_dir or die $!;
  

chdir $local_dir or die $!;

my %configuration = (
                     top_directory => $local_dir,
                     remote_directory => $remote_dir,
                     remote_url => 'http://www.test.com',
                     upload_pkg => 'App::Followme::UploadLocal',
                    );

#----------------------------------------------------------------------
# Test read and write files

do {
    my $up = App::Followme::UploadSite->new(%configuration);

    my $user_ok = 'gandalf';
    my $password_ok = 'wizzard';



( run in 2.462 seconds using v1.01-cache-2.11-cpan-b16cb0d3907 )