s3repo 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circle-ruby +3 -0
- data/.prospectus +21 -7
- data/.rubocop.yml +5 -2
- data/Gemfile +0 -1
- data/README.md +1 -1
- data/Rakefile +1 -2
- data/bin/s3repo +31 -8
- data/circle.yml +7 -4
- data/lib/s3repo.rb +2 -0
- data/lib/s3repo/base.rb +4 -8
- data/lib/s3repo/cache.rb +13 -10
- data/lib/s3repo/client.rb +21 -8
- data/lib/s3repo/metadata.rb +12 -24
- data/lib/s3repo/repo.rb +17 -15
- data/lib/s3repo/signer.rb +17 -0
- data/lib/s3repo/templates.rb +52 -0
- data/lib/s3repo/version.rb +2 -1
- data/s3repo.gemspec +12 -9
- data/spec/spec_helper.rb +3 -0
- metadata +48 -27
- data/spec/fixtures/cassettes/cache.yml +0 -547
- data/spec/fixtures/cassettes/etag_cache.yml +0 -590
- data/spec/fixtures/cassettes/nil_cache.yml +0 -46
- data/spec/s3repo/base_spec.rb +0 -71
- data/spec/s3repo/cache_spec.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77fb43c11e189c5bfc7c347fa6b0d2efe566f9ff
|
4
|
+
data.tar.gz: 2ce120f3afd0e0b63a6d2f63c84822c3b974bc95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0c201ab4c0e8eefc8e7d2ba2490d92fdc9eb6e989c2b1a5cec9436580ca8c0ef5bf874052fac4056725343a9ccfbe5f96747cf1931297d81df5cee6ee251cf5
|
7
|
+
data.tar.gz: b2acfdd8d6386b69bddbd772d836b40d825a58b8adcbdf6a0ee64c484e397c94cbaf5d2e8cb99f303030bb031f24ed2e31e2bceab89fa801b587cea1fbfa0da7
|
data/.circle-ruby
ADDED
data/.prospectus
CHANGED
@@ -1,11 +1,25 @@
|
|
1
|
+
Prospectus.extra_dep('file', 'prospectus_circleci')
|
2
|
+
|
3
|
+
my_slug = 'amylum/s3repo'
|
4
|
+
|
1
5
|
item do
|
2
|
-
|
3
|
-
static
|
4
|
-
set 'green'
|
5
|
-
end
|
6
|
+
noop
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
deps do
|
9
|
+
item do
|
10
|
+
name 'gems'
|
11
|
+
|
12
|
+
expected do
|
13
|
+
static
|
14
|
+
set 'green'
|
15
|
+
end
|
16
|
+
|
17
|
+
actual do
|
18
|
+
gemnasium
|
19
|
+
slug my_slug
|
20
|
+
end
|
21
|
+
end
|
10
22
|
end
|
23
|
+
|
24
|
+
extend ProspectusCircleci::Build.new(my_slug)
|
11
25
|
end
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@ s3repo
|
|
3
3
|
|
4
4
|
[![Gem Version](https://img.shields.io/gem/v/s3repo.svg)](https://rubygems.org/gems/s3repo)
|
5
5
|
[![Dependency Status](https://img.shields.io/gemnasium/amylum/s3repo.svg)](https://gemnasium.com/amylum/s3repo)
|
6
|
-
[![Build Status](https://img.shields.io/circleci/project/amylum/s3repo.svg)](https://circleci.com/gh/amylum/s3repo)
|
6
|
+
[![Build Status](https://img.shields.io/circleci/project/amylum/s3repo/master.svg)](https://circleci.com/gh/amylum/s3repo)
|
7
7
|
[![Coverage Status](https://img.shields.io/codecov/c/github/amylum/s3repo.svg)](https://codecov.io/github/amylum/s3repo)
|
8
8
|
[![Code Quality](https://img.shields.io/codacy/eef971ff937642219c1d4094001c33e7.svg)](https://www.codacy.com/app/akerl/s3repo)
|
9
9
|
[![MIT Licensed](https://img.shields.io/badge/license-MIT-green.svg)](https://tldrlegal.com/license/mit-license)
|
data/Rakefile
CHANGED
@@ -7,8 +7,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
7
7
|
|
8
8
|
desc 'Run Rubocop on the gem'
|
9
9
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
10
|
-
task.patterns = ['lib/**/*.rb', 'spec/**/*.rb', 'bin/*']
|
11
10
|
task.fail_on_error = true
|
12
11
|
end
|
13
12
|
|
14
|
-
task default: [
|
13
|
+
task default: %i[spec rubocop build install]
|
data/bin/s3repo
CHANGED
@@ -2,49 +2,72 @@
|
|
2
2
|
|
3
3
|
require 's3repo'
|
4
4
|
require 'mercenary'
|
5
|
+
require 'yaml'
|
6
|
+
require 'cymbal'
|
5
7
|
|
6
8
|
def find(pattern, limits)
|
7
9
|
Dir.glob(pattern).select { |x| !limits || limits.include?(File.dirname(x)) }
|
8
10
|
end
|
9
11
|
|
12
|
+
def common_opts(cmd)
|
13
|
+
cmd.option :config_file, '-c', '--config FILE', 'Path of config file'
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_config(file)
|
17
|
+
file ||= 'config.yml'
|
18
|
+
file = File.expand_path(file)
|
19
|
+
raise("Config file not found: #{file}") unless File.exist? file
|
20
|
+
Cymbal.symbolize YAML.safe_load(File.read(file))
|
21
|
+
end
|
22
|
+
|
23
|
+
def repo(options)
|
24
|
+
config = load_config(options[:config_file])
|
25
|
+
S3Repo.new(config)
|
26
|
+
end
|
27
|
+
|
28
|
+
# rubocop:disable Metrics/BlockLength
|
10
29
|
Mercenary.program(:s3repo) do |p|
|
11
30
|
p.version S3Repo::VERSION
|
12
31
|
p.description 'Package management tool for Archlinux repos'
|
13
32
|
p.syntax 's3repo <subcommand> [args]'
|
14
33
|
|
15
34
|
p.command(:build) do |c|
|
35
|
+
common_opts(c)
|
16
36
|
c.syntax 'build [package...]'
|
17
37
|
c.description 'Build package files from PKGBUILDs'
|
18
38
|
|
19
|
-
c.action do |args,
|
20
|
-
|
39
|
+
c.action do |args, opts|
|
40
|
+
repo(opts).build_packages find('*/PKGBUILD', args)
|
21
41
|
end
|
22
42
|
end
|
23
43
|
|
24
44
|
p.command(:upload) do |c|
|
45
|
+
common_opts(c)
|
25
46
|
c.syntax 'upload [package...]'
|
26
47
|
c.description 'Upload packages to repo'
|
27
48
|
|
28
|
-
c.action do |args,
|
29
|
-
|
49
|
+
c.action do |args, opts|
|
50
|
+
repo(opts).add_packages find('*/*.pkg.tar.xz', args)
|
30
51
|
end
|
31
52
|
end
|
32
53
|
|
33
54
|
p.command(:remove) do |c|
|
55
|
+
common_opts(c)
|
34
56
|
c.syntax 'remove [package...]'
|
35
57
|
c.description 'Remove packages from repo DB'
|
36
58
|
|
37
|
-
c.action do |args,
|
38
|
-
|
59
|
+
c.action do |args, opts|
|
60
|
+
repo(opts).remove_packages args
|
39
61
|
end
|
40
62
|
end
|
41
63
|
|
42
64
|
p.command(:prune) do |c|
|
65
|
+
common_opts(c)
|
43
66
|
c.syntax 'prune'
|
44
67
|
c.description 'Prune orphaned files from the repo'
|
45
68
|
|
46
|
-
c.action do
|
47
|
-
|
69
|
+
c.action do |_, opts|
|
70
|
+
repo(opts).prune_files
|
48
71
|
end
|
49
72
|
end
|
50
73
|
|
data/circle.yml
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
machine:
|
2
|
+
environment:
|
3
|
+
AWS_ACCESS_KEY_ID: '1'
|
4
|
+
AWS_SECRET_ACCESS_KEY: '1'
|
1
5
|
dependencies:
|
2
6
|
override:
|
3
|
-
|
4
|
-
|
7
|
+
- 'for i in $(cat .circle-ruby) ; do rvm-exec $i gem update --system --no-doc || exit 1 ; done'
|
8
|
+
- 'for i in $(cat .circle-ruby) ; do rvm-exec $i bundle install || exit 1 ; done'
|
5
9
|
test:
|
6
10
|
override:
|
7
|
-
|
8
|
-
- 'rvm-exec 2.2.2 bundle exec rake'
|
11
|
+
- 'for i in $(cat .circle-ruby) ; do rvm-exec $i bundle exec rake || exit 1 ; done'
|
data/lib/s3repo.rb
CHANGED
data/lib/s3repo/base.rb
CHANGED
@@ -13,23 +13,19 @@ module S3Repo
|
|
13
13
|
def run(cmd)
|
14
14
|
results = `#{cmd} 2>&1`
|
15
15
|
return results if $CHILD_STATUS.success?
|
16
|
-
|
16
|
+
raise "Failed running #{cmd}:\n#{results}"
|
17
17
|
end
|
18
18
|
|
19
19
|
def bucket
|
20
|
-
@
|
21
|
-
return @bucket if @bucket
|
22
|
-
fail('No bucket given')
|
20
|
+
@options[:bucket] || raise('No bucket given')
|
23
21
|
end
|
24
22
|
|
25
23
|
def client
|
26
|
-
@
|
24
|
+
@options[:client] ||= Client.new(@options)
|
27
25
|
end
|
28
26
|
|
29
27
|
def file_cache
|
30
|
-
@file_cache ||= @options[:file_cache] || Cache.new(
|
31
|
-
client: client, tmpdir: @options[:tmpdir]
|
32
|
-
)
|
28
|
+
@file_cache ||= @options[:file_cache] || Cache.new(@options)
|
33
29
|
end
|
34
30
|
end
|
35
31
|
end
|
data/lib/s3repo/cache.rb
CHANGED
@@ -7,7 +7,6 @@ module S3Repo
|
|
7
7
|
# Cache object, stores S3 objects on disk
|
8
8
|
class Cache < Base
|
9
9
|
TMPDIRS = [
|
10
|
-
ENV['S3REPO_TMPDIR'],
|
11
10
|
ENV['TMPDIR'],
|
12
11
|
Dir.tmpdir,
|
13
12
|
'/tmp/s3repo'
|
@@ -18,20 +17,18 @@ module S3Repo
|
|
18
17
|
[partialdir, cachedir].each { |x| FileUtils.mkdir_p x }
|
19
18
|
end
|
20
19
|
|
21
|
-
def serve(key, refresh = true)
|
22
|
-
File.open(download(key, refresh), &:read)
|
23
|
-
rescue Aws::S3::Errors::NoSuchKey
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
20
|
def download(key, refresh = true)
|
30
21
|
path = expand_path key
|
31
22
|
get_object(key, path) if refresh || !cached?(path)
|
32
23
|
path
|
33
24
|
end
|
34
25
|
|
26
|
+
private
|
27
|
+
|
28
|
+
def file_cache
|
29
|
+
raise('Tried to call file_cache recursively')
|
30
|
+
end
|
31
|
+
|
35
32
|
def expand_path(key)
|
36
33
|
File.absolute_path(key, cachedir)
|
37
34
|
end
|
@@ -71,7 +68,13 @@ module S3Repo
|
|
71
68
|
end
|
72
69
|
|
73
70
|
def tmpdir
|
74
|
-
@tmpdir ||=
|
71
|
+
@tmpdir ||= Dir.mktmpdir 's3repo', tmpdir_root
|
72
|
+
end
|
73
|
+
|
74
|
+
def tmpdir_root
|
75
|
+
@tmpdir_root ||= File.absolute_path(
|
76
|
+
@options[:tmpdir] || TMPDIRS.compact.first
|
77
|
+
)
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
data/lib/s3repo/client.rb
CHANGED
@@ -5,21 +5,33 @@ module S3Repo
|
|
5
5
|
# AWS API client
|
6
6
|
class Client
|
7
7
|
def initialize(params = {})
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@options = params
|
9
|
+
@api = Aws::S3::Client.new(region: region)
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def respond_to_missing?(method, include_all = false)
|
13
13
|
@api.respond_to?(method, include_all) || super
|
14
14
|
end
|
15
15
|
|
16
|
-
def upload
|
16
|
+
def upload(key, body)
|
17
17
|
puts "Uploading #{key}"
|
18
|
-
put_object key: key, body:
|
18
|
+
put_object key: key, body: body
|
19
|
+
end
|
20
|
+
|
21
|
+
def upload_file(key, path)
|
22
|
+
upload(key, File.open(path).read)
|
19
23
|
end
|
20
24
|
|
21
25
|
private
|
22
26
|
|
27
|
+
def region
|
28
|
+
@options[:region] || raise('AWS region not set')
|
29
|
+
end
|
30
|
+
|
31
|
+
def bucket
|
32
|
+
@options[:bucket] || raise('Bucket not set')
|
33
|
+
end
|
34
|
+
|
23
35
|
def method_missing(method, *args, &block)
|
24
36
|
return super unless @api.respond_to?(method)
|
25
37
|
define_singleton_method(method) do |*singleton_args|
|
@@ -30,10 +42,11 @@ module S3Repo
|
|
30
42
|
end
|
31
43
|
|
32
44
|
def build_params(args)
|
33
|
-
|
45
|
+
raise 'Too many arguments given' if args.size > 1
|
34
46
|
params = args.first || {}
|
35
|
-
|
36
|
-
|
47
|
+
raise 'Argument must be a hash' unless params.is_a? Hash
|
48
|
+
params[:bucket] ||= bucket
|
49
|
+
params
|
37
50
|
end
|
38
51
|
end
|
39
52
|
end
|
data/lib/s3repo/metadata.rb
CHANGED
@@ -5,11 +5,6 @@ module S3Repo
|
|
5
5
|
##
|
6
6
|
# Metadata object, represents repo's DB file
|
7
7
|
class Metadata < Base
|
8
|
-
def initialize(params = {})
|
9
|
-
super
|
10
|
-
FileUtils.mkdir_p db_dir
|
11
|
-
end
|
12
|
-
|
13
8
|
def add_packages(paths)
|
14
9
|
@db_path = nil
|
15
10
|
paths.each do |path|
|
@@ -29,38 +24,31 @@ module S3Repo
|
|
29
24
|
end
|
30
25
|
|
31
26
|
def update!
|
32
|
-
sign_db if
|
33
|
-
client.
|
27
|
+
sign_db if @options[:sign_db]
|
28
|
+
client.upload_file('repo.db', db_path)
|
29
|
+
client.upload_file('repo.db.tar.xz', db_path)
|
34
30
|
end
|
35
31
|
|
36
32
|
def packages
|
37
33
|
return @packages if @packages
|
38
|
-
cmd = "
|
34
|
+
cmd = "bsdtar tf #{db_path}"
|
39
35
|
@packages = run(cmd).split.map { |x| x.split('/').first }.uniq
|
40
36
|
end
|
41
37
|
|
42
38
|
private
|
43
39
|
|
44
|
-
def
|
45
|
-
|
46
|
-
client.upload!('repo.db.sig', "#{db_path}.sig")
|
47
|
-
end
|
48
|
-
|
49
|
-
def db_path
|
50
|
-
@db_path ||= download_db
|
40
|
+
def signer
|
41
|
+
@options[:signer] ||= Signer.new(@options)
|
51
42
|
end
|
52
43
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
tmpfile.path
|
44
|
+
def sign_db
|
45
|
+
sig_path = signer.sign(db_path)
|
46
|
+
client.upload_file('repo.db.sig', sig_path)
|
47
|
+
client.upload_file('repo.db.tar.xz.sig', sig_path)
|
58
48
|
end
|
59
49
|
|
60
|
-
def
|
61
|
-
@
|
62
|
-
@options[:tmpdir] || Cache::TMPDIRS.compact.first
|
63
|
-
)
|
50
|
+
def db_path
|
51
|
+
@db_path ||= file_cache.download('repo.db.tar.xz')
|
64
52
|
end
|
65
53
|
end
|
66
54
|
end
|
data/lib/s3repo/repo.rb
CHANGED
@@ -5,25 +5,23 @@ module S3Repo
|
|
5
5
|
##
|
6
6
|
# Repo object, represents an Arch repo inside an S3 bucket
|
7
7
|
class Repo < Base
|
8
|
-
def
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
def build_packages(paths, makepkg_flags = '')
|
8
|
+
def build_packages(paths)
|
13
9
|
paths.each do |path|
|
14
10
|
dir = File.dirname(path)
|
15
11
|
puts "Building #{File.basename(dir)}"
|
16
|
-
Dir.chdir(dir) { run "makepkg #{makepkg_flags}" }
|
12
|
+
Dir.chdir(dir) { run "makepkg #{@options[:makepkg_flags]}" }
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
20
16
|
def add_packages(paths)
|
21
17
|
paths.select! { |path| upload_package(path) }
|
22
18
|
metadata.add_packages(paths) unless paths.empty?
|
19
|
+
templates.update! unless paths.empty?
|
23
20
|
end
|
24
21
|
|
25
22
|
def remove_packages(packages)
|
26
23
|
metadata.remove_packages(packages)
|
24
|
+
templates.update!
|
27
25
|
end
|
28
26
|
|
29
27
|
def prune_files
|
@@ -47,19 +45,15 @@ module S3Repo
|
|
47
45
|
!packages.find { |x| x.key == key }.nil?
|
48
46
|
end
|
49
47
|
|
50
|
-
def serve(key)
|
51
|
-
refresh = !key.match(/\.pkg\.tar\.xz$/)
|
52
|
-
file_cache.serve(key, refresh)
|
53
|
-
end
|
54
|
-
|
55
48
|
private
|
56
49
|
|
57
50
|
def upload_package(path)
|
58
51
|
key = File.basename(path)
|
59
|
-
sig_key, sig_path = [key, path].map { |x| x + '.sig' }
|
60
52
|
return false if include? key
|
61
|
-
|
62
|
-
|
53
|
+
sig_path = signer.sign(path)
|
54
|
+
sig_key = key + '.sig'
|
55
|
+
client.upload_file(sig_key, sig_path) if @options[:sign_packages]
|
56
|
+
client.upload_file(key, path)
|
63
57
|
true
|
64
58
|
end
|
65
59
|
|
@@ -70,7 +64,15 @@ module S3Repo
|
|
70
64
|
end
|
71
65
|
|
72
66
|
def metadata
|
73
|
-
@metadata ||= Metadata.new(
|
67
|
+
@options[:metadata] ||= Metadata.new(@options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def signer
|
71
|
+
@options[:signer] ||= Signer.new(@options)
|
72
|
+
end
|
73
|
+
|
74
|
+
def templates
|
75
|
+
@templates ||= Templates.new(@options)
|
74
76
|
end
|
75
77
|
|
76
78
|
def package_cache
|