Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: CI

on:
push:
branches: [main, master]
pull_request:
workflow_dispatch:

jobs:
test:
name: Unit tests (Ruby ${{ matrix.ruby }})
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental == true }}
strategy:
fail-fast: false
matrix:
include:
- ruby: '3.0'
- ruby: '3.1'
- ruby: '3.2'
- ruby: '3.3'
- ruby: '3.4'
- ruby: '4.0'
# ruby-head (trunk); failures here must not block CI.
- ruby: 'head'
experimental: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
with:
ruby-version: ${{ matrix.ruby }}
- run: bundle install
- run: bundle exec rake test

test-integration:
name: Integration tests (vsftpd via Docker)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
with:
ruby-version: '4.0'
- run: bundle install
- run: bundle exec rake test:integration

lint:
name: Lint and package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
with:
ruby-version: '4.0'
- run: bundle install
- run: bundle exec rake rubocop
- run: gem build ftpsync.gemspec
16 changes: 16 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins:
- rubocop-minitest
- rubocop-rake

AllCops:
NewCops: enable
TargetRubyVersion: 2.6

Metrics/AbcSize:
Max: 20

Metrics/ClassLength:
Max: 200

Metrics/MethodLength:
Max: 20
4 changes: 0 additions & 4 deletions .travis.yml

This file was deleted.

10 changes: 10 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
# frozen_string_literal: true

source 'https://rubygems.org'

# Specify your gem's dependencies in ftpsync.gemspec
gemspec

group :development, :test do
gem 'minitest', '~> 5.0'
gem 'rake', '~> 13.0'
gem 'rubocop', '~> 1.0'
gem 'rubocop-minitest', '~> 0.40'
gem 'rubocop-rake', '~> 0.7'
end
56 changes: 51 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# FtpSync

[![CI](https://github.com/Quintasan/ftpsync/actions/workflows/ci.yml/badge.svg)](https://github.com/Quintasan/ftpsync/actions/workflows/ci.yml)

A simple library for synchronizing from/to FTP servers.

## Installation
Expand All @@ -25,22 +27,66 @@ example = FtpSync::Simple.new "ftp.example.com", "username", "password"
example.pull_dir('remotepath', 'localpath')
```

### Options

`FtpSync::Simple#new` accepts an options hash:

| Option | Default | Description |
|------------|---------|------------------------------------|
| `:port` | `21` | FTP port to connect to |
| `:passive` | `false` | Use passive mode |
| `:verbose` | `false` | Log progress to stderr |

`FtpSync::Simple#pull_dir` accepts an options hash:

| Option | Description |
|----------------|------------------------------------------------------------|
| `:since` | Skip files that already exist locally and are up to date |
| `:skip_errors` | Rescue `Net::FTPPermError` and continue instead of raising |

> **Note:** `:since` compares size and the mtime reported by the server's
> `LIST` output, which usually has minute precision. A remote file of the
> same size that was modified within the same minute as the local copy may
> therefore be skipped.

Passing a block to `pull_dir` invokes it with the local path of each
downloaded file:

```ruby
example.pull_dir('remotepath', 'localpath', since: true) do |file|
process(file)
end
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests and RuboCop (or `rake test` / `rake rubocop` individually). You can also run `bin/console` for an interactive prompt that will allow you to experiment.

### Integration tests (requires Docker)

The integration suite runs against a real FTP server
([garethflowers/ftp-server](https://garethflowers.dev/docker-ftp-server/),
vsftpd) in a Docker container:

$ rake test:integration

The container listens on `127.0.0.1:2121` (control) and
`127.0.0.1:40000-40009` (passive data). The tests are skipped automatically
if Docker is not available, and the container is created and removed for
each run. Override the credentials and control port with the
`FTPSYNC_TEST_USER`, `FTPSYNC_TEST_PASS` and `FTPSYNC_TEST_FTP_PORT`
environment variables.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/quintasan/ftpsync. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.

Bug reports and pull requests are welcome on GitHub at https://github.com/quintasan/ftpsync. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org) code of conduct.

## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).


## Credits

This gem is a basically stripped down version of [orlando/ftp_sync](https://github.com/orlando/ftp_sync) which I couldn't get to work.
This gem is a basically stripped down version of [orlando/ftp_sync](https://github.com/orlando/ftp_sync) which I couldn't get to work.
24 changes: 18 additions & 6 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
require "bundler/gem_tasks"
require "rake/testtask"
# frozen_string_literal: true

require 'bundler/gem_tasks'
require 'rake/testtask'
require 'rubocop/rake_task'

Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList['test/**/*_test.rb']
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/*_test.rb']
end

desc 'Run integration tests against a Dockerized FTP server'
Rake::TestTask.new(:'test:integration') do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/integration/**/*_test.rb']
end

task :default => :test
RuboCop::RakeTask.new

task default: %i[test rubocop]
7 changes: 4 additions & 3 deletions bin/console
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"
require "ftpsync"
require 'bundler/setup'
require 'ftpsync'

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
Expand All @@ -10,5 +11,5 @@ require "ftpsync"
# require "pry"
# Pry.start

require "irb"
require 'irb'
IRB.start
44 changes: 25 additions & 19 deletions ftpsync.gemspec
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'ftpsync/version'
# frozen_string_literal: true

require_relative 'lib/ftpsync/version'

Gem::Specification.new do |spec|
spec.name = "ftpsync"
spec.version = FtpSync::VERSION
spec.authors = ["Michał Zając"]
spec.email = ["rubygems.org@quintasan.pl"]
spec.name = 'ftpsync'
spec.version = FtpSync::VERSION
spec.authors = ['Michał Zając']
spec.email = ['rubygems.org@quintasan.pl']

spec.summary = %q{A simple library for synchronizing from/to FTP servers.}
spec.homepage = "https://github.com/Quintasan/ftpsync"
spec.license = "MIT"
spec.summary = 'A simple library for synchronizing from/to FTP servers.'
spec.description = 'Recursively pull directory trees from FTP servers, with support ' \
'for incremental syncs and per-file callbacks.'
spec.homepage = 'https://github.com/Quintasan/ftpsync'
spec.license = 'MIT'
spec.required_ruby_version = '>= 2.6.0'

spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.metadata = {
'source_code_uri' => spec.homepage,
'rubygems_mfa_required' => 'true'
}

spec.add_dependency "net-ftp-list", ">= 3.2.8"
spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject do |f|
f.match?(%r{^(test|spec|features)/|^\.github/}) || !File.file?(f)
end
end
spec.require_paths = ['lib']

spec.add_development_dependency "bundler", "~> 1.10"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "minitest"
spec.add_dependency 'net-ftp'
spec.add_dependency 'net-ftp-list', '>= 3.2.8'
end
Loading