dpl 1.10.17.travis.6637.6 → 2.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +74 -0
- data/CONTRIBUTING.md +392 -0
- data/Gemfile +17 -3
- data/Gemfile.lock +373 -0
- data/LICENSE +16 -19
- data/NOTES.md +275 -0
- data/README.md +1977 -707
- data/Rakefile +2 -2
- data/bin/dpl +7 -3
- data/lib/dpl.rb +20 -0
- data/lib/dpl/assets/atlas/install +19 -0
- data/lib/dpl/assets/dpl/README.erb.md +133 -0
- data/lib/dpl/assets/dpl/git_ssh +2 -0
- data/lib/dpl/assets/git/detect_private_key +8 -0
- data/lib/dpl/assets/hephy/filter_log +3 -0
- data/lib/dpl/assets/pypi/install +4 -0
- data/lib/dpl/assets/scalingo/install +6 -0
- data/lib/dpl/cli.rb +36 -48
- data/lib/dpl/ctx.rb +2 -0
- data/lib/dpl/ctx/bash.rb +543 -0
- data/lib/dpl/ctx/test.rb +242 -0
- data/lib/dpl/helper/assets.rb +36 -0
- data/lib/dpl/helper/cmd.rb +167 -0
- data/lib/dpl/helper/config_file.rb +47 -0
- data/lib/dpl/helper/env.rb +39 -0
- data/lib/dpl/helper/interpolate.rb +126 -0
- data/lib/dpl/helper/memoize.rb +20 -0
- data/lib/dpl/helper/squiggle.rb +22 -0
- data/lib/dpl/helper/zip.rb +69 -0
- data/lib/dpl/provider.rb +562 -234
- data/lib/dpl/provider/dsl.rb +369 -0
- data/lib/dpl/provider/examples.rb +128 -0
- data/lib/dpl/provider/status.rb +59 -0
- data/lib/dpl/providers.rb +40 -0
- data/lib/dpl/providers/anynines.rb +65 -0
- data/lib/dpl/providers/atlas.rb +49 -0
- data/lib/dpl/providers/azure_web_apps.rb +59 -0
- data/lib/dpl/providers/bintray.rb +313 -0
- data/lib/dpl/providers/bluemixcloudfoundry.rb +92 -0
- data/lib/dpl/providers/boxfuse.rb +48 -0
- data/lib/dpl/providers/cargo.rb +19 -0
- data/lib/dpl/providers/chef_supermarket.rb +128 -0
- data/lib/dpl/providers/cloud66.rb +40 -0
- data/lib/dpl/providers/cloudfiles.rb +56 -0
- data/lib/dpl/providers/cloudfoundry.rb +81 -0
- data/lib/dpl/providers/codedeploy.rb +179 -0
- data/lib/dpl/providers/datica.rb +60 -0
- data/lib/dpl/providers/elasticbeanstalk.rb +195 -0
- data/lib/dpl/providers/engineyard.rb +107 -0
- data/lib/dpl/providers/firebase.rb +41 -0
- data/lib/dpl/providers/gae.rb +74 -0
- data/lib/dpl/providers/gcs.rb +105 -0
- data/lib/dpl/providers/hackage.rb +47 -0
- data/lib/dpl/providers/hephy.rb +101 -0
- data/lib/dpl/providers/heroku.rb +111 -0
- data/lib/dpl/providers/heroku/api.rb +119 -0
- data/lib/dpl/providers/heroku/git.rb +50 -0
- data/lib/dpl/providers/lambda.rb +202 -0
- data/lib/dpl/providers/launchpad.rb +74 -0
- data/lib/dpl/providers/netlify.rb +30 -0
- data/lib/dpl/providers/npm.rb +88 -0
- data/lib/dpl/providers/openshift.rb +46 -0
- data/lib/dpl/providers/opsworks.rb +142 -0
- data/lib/dpl/providers/packagecloud.rb +190 -0
- data/lib/dpl/providers/pages.rb +17 -0
- data/lib/dpl/providers/pages/api.rb +102 -0
- data/lib/dpl/providers/pages/git.rb +251 -0
- data/lib/dpl/providers/puppetforge.rb +44 -0
- data/lib/dpl/providers/pypi.rb +120 -0
- data/lib/dpl/providers/releases.rb +214 -0
- data/lib/dpl/providers/rubygems.rb +89 -0
- data/lib/dpl/providers/s3.rb +243 -0
- data/lib/dpl/providers/scalingo.rb +63 -0
- data/lib/dpl/providers/script.rb +28 -0
- data/lib/dpl/providers/snap.rb +59 -0
- data/lib/dpl/providers/surge.rb +55 -0
- data/lib/dpl/providers/testfairy.rb +93 -0
- data/lib/dpl/providers/transifex.rb +66 -0
- data/lib/dpl/support/aws_sdk_patch.rb +23 -0
- data/lib/dpl/support/gems.rb +69 -0
- data/lib/dpl/support/gstore_patch.rb +6 -0
- data/lib/dpl/support/version.rb +83 -0
- data/lib/dpl/version.rb +2 -2
- metadata +98 -169
- data/.coveralls.yml +0 -1
- data/.github/CONTRIBUTING.md +0 -173
- data/.github/stale.yml +0 -53
- data/.gitignore +0 -13
- data/.rspec +0 -2
- data/.travis.yml +0 -56
- data/dpl-anynines.gemspec +0 -3
- data/dpl-atlas.gemspec +0 -3
- data/dpl-azure_webapps.gemspec +0 -3
- data/dpl-bintray.gemspec +0 -3
- data/dpl-bitballoon.gemspec +0 -3
- data/dpl-bluemix_cloud_foundry.gemspec +0 -3
- data/dpl-boxfuse.gemspec +0 -3
- data/dpl-cargo.gemspec +0 -3
- data/dpl-catalyze.gemspec +0 -3
- data/dpl-chef_supermarket.gemspec +0 -20
- data/dpl-cloud66.gemspec +0 -3
- data/dpl-cloud_files.gemspec +0 -3
- data/dpl-cloud_foundry.gemspec +0 -3
- data/dpl-code_deploy.gemspec +0 -3
- data/dpl-deis.gemspec +0 -3
- data/dpl-elastic_beanstalk.gemspec +0 -3
- data/dpl-engine_yard.gemspec +0 -3
- data/dpl-firebase.gemspec +0 -3
- data/dpl-gae.gemspec +0 -3
- data/dpl-gcs.gemspec +0 -3
- data/dpl-hackage.gemspec +0 -3
- data/dpl-hephy.gemspec +0 -3
- data/dpl-heroku.gemspec +0 -3
- data/dpl-lambda.gemspec +0 -3
- data/dpl-launchpad.gemspec +0 -3
- data/dpl-npm.gemspec +0 -3
- data/dpl-openshift.gemspec +0 -3
- data/dpl-ops_works.gemspec +0 -3
- data/dpl-packagecloud.gemspec +0 -3
- data/dpl-pages.gemspec +0 -3
- data/dpl-puppet_forge.gemspec +0 -3
- data/dpl-pypi.gemspec +0 -3
- data/dpl-releases.gemspec +0 -8
- data/dpl-rubygems.gemspec +0 -3
- data/dpl-s3.gemspec +0 -3
- data/dpl-scalingo.gemspec +0 -3
- data/dpl-script.gemspec +0 -3
- data/dpl-snap.gemspec +0 -3
- data/dpl-surge.gemspec +0 -3
- data/dpl-testfairy.gemspec +0 -3
- data/dpl-transifex.gemspec +0 -3
- data/dpl.gemspec +0 -3
- data/gemspec_helper.rb +0 -51
- data/lib/dpl/error.rb +0 -3
- data/notes/engine_yard.md +0 -1
- data/notes/heroku.md +0 -3
- data/spec/cli_spec.rb +0 -36
- data/spec/provider_spec.rb +0 -191
- data/spec/spec_helper.rb +0 -20
@@ -0,0 +1,63 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Scalingo < Provider
|
4
|
+
status :alpha
|
5
|
+
|
6
|
+
description sq(<<-str)
|
7
|
+
tbd
|
8
|
+
str
|
9
|
+
|
10
|
+
required :api_token, [:username, :password]
|
11
|
+
|
12
|
+
opt '--app APP', default: :repo_name
|
13
|
+
opt '--api_token TOKEN', 'Scalingo API token', alias: :api_key, deprecated: :api_key
|
14
|
+
opt '--username NAME', 'Scalingo username'
|
15
|
+
opt '--password PASS', 'Scalingo password', secret: true
|
16
|
+
opt '--region REGION', 'Scalingo region', default: 'agora-fr1', enum: %w(agora-fr1 osc-fr1)
|
17
|
+
opt '--remote REMOTE', 'Git remote name', default: 'scalingo-dpl'
|
18
|
+
opt '--branch BRANCH', 'Git branch', default: 'master'
|
19
|
+
opt '--timeout SEC', 'Timeout for Scalingo CLI commands', default: 60, type: :integer
|
20
|
+
|
21
|
+
needs :git, :ssh_key
|
22
|
+
|
23
|
+
cmds login_key: 'timeout %{timeout} ./scalingo login --api-token %{api_token} > /dev/null',
|
24
|
+
login_creds: 'echo -e \"%{username}\n%{password}\" | timeout %{timeout} ./scalingo login > /dev/null',
|
25
|
+
add_key: 'timeout %{timeout} ./scalingo keys-add dpl_tmp_key %{key}',
|
26
|
+
remove_key: 'timeout %{timeout} ./scalingo keys-remove dpl_tmp_key',
|
27
|
+
git_setup: './scalingo --app %{app} git-setup --remote %{remote}',
|
28
|
+
push: 'git push %{remote} HEAD:%{branch} -f'
|
29
|
+
|
30
|
+
errs install: 'Failed to install the Scalingo CLI.',
|
31
|
+
login: 'Failed to authenticate with the Scalingo API.',
|
32
|
+
add_key: 'Failed to add the ssh key.',
|
33
|
+
remove_key: 'Failed to remove the ssh key.',
|
34
|
+
git_setup: 'Failed to add the git remote.',
|
35
|
+
push: 'Failed to push the app.'
|
36
|
+
|
37
|
+
def install
|
38
|
+
script :install
|
39
|
+
ENV['SCALINGO_REGION'] = region if region?
|
40
|
+
end
|
41
|
+
|
42
|
+
def login
|
43
|
+
shell api_token ? :login_key : :login_creds, assert: err(:login)
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_key(key, type = nil)
|
47
|
+
shell :add_key, key: key
|
48
|
+
end
|
49
|
+
|
50
|
+
def setup
|
51
|
+
shell :git_setup
|
52
|
+
end
|
53
|
+
|
54
|
+
def deploy
|
55
|
+
shell :push
|
56
|
+
end
|
57
|
+
|
58
|
+
def remove_key
|
59
|
+
shell :remove_key
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Script < Provider
|
4
|
+
status :alpha
|
5
|
+
|
6
|
+
summary 'Minimal provider that executes a custom command'
|
7
|
+
|
8
|
+
description sq(<<-str)
|
9
|
+
This deployment provider executes a single, custom command. This is
|
10
|
+
usually a script that is contained in your repository, but it can be
|
11
|
+
any command executable in the build environment.
|
12
|
+
|
13
|
+
It is possible to pass arguments to a script deployment like so:
|
14
|
+
|
15
|
+
dpl script -s './scripts/deploy.sh production --verbose'
|
16
|
+
|
17
|
+
Deployment will be marked a failure if the script exits with nonzero
|
18
|
+
status.
|
19
|
+
str
|
20
|
+
|
21
|
+
opt '-s', '--script SCRIPT', 'The script to execute', required: true
|
22
|
+
|
23
|
+
def deploy
|
24
|
+
shell script, assert: 'Script failed with status %{status}'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Snap < Provider
|
4
|
+
status :dev
|
5
|
+
|
6
|
+
description sq(<<-str)
|
7
|
+
tbd
|
8
|
+
str
|
9
|
+
|
10
|
+
env :snap
|
11
|
+
|
12
|
+
opt '--token TOKEN', 'Snap API token', required: true, secret: true
|
13
|
+
opt '--snap STR', 'Path to the snap to be pushed (can be a glob)', default: '**/*.snap'
|
14
|
+
opt '--channel CHAN', 'Channel into which the snap will be released', default: 'edge'
|
15
|
+
|
16
|
+
apt 'snapd', 'snap'
|
17
|
+
|
18
|
+
cmds install: 'sudo snap install snapcraft --classic',
|
19
|
+
login: 'snapcraft login --with %{token}',
|
20
|
+
deploy: 'snapcraft push %{snap_path} --release=%{channel}'
|
21
|
+
|
22
|
+
msgs login: 'Attemping to login ...',
|
23
|
+
no_snaps: 'No snap found matching %{snap}',
|
24
|
+
multiple_snaps: 'Multiple snaps found matching %{snap}: %{snap_paths}',
|
25
|
+
deploy: 'Pushing snap %{snap_path}'
|
26
|
+
|
27
|
+
def install
|
28
|
+
return if which 'snapcraft'
|
29
|
+
shell :install
|
30
|
+
ENV['PATH'] += ':/snap/bin'
|
31
|
+
end
|
32
|
+
|
33
|
+
def login
|
34
|
+
shell :login, assert: 'Failed to authenticate: %{err}', success: '%{out}', capture: true
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate
|
38
|
+
error :no_snaps if snaps.empty?
|
39
|
+
error :multiple_snaps if snaps.size > 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def deploy
|
43
|
+
shell :deploy
|
44
|
+
end
|
45
|
+
|
46
|
+
def snap_path
|
47
|
+
snaps.first
|
48
|
+
end
|
49
|
+
|
50
|
+
def snap_paths
|
51
|
+
snaps.join(', ')
|
52
|
+
end
|
53
|
+
|
54
|
+
def snaps
|
55
|
+
@snaps ||= Dir[snap].sort
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Providers
|
5
|
+
class Surge < Provider
|
6
|
+
status :alpha
|
7
|
+
|
8
|
+
description sq(<<-str)
|
9
|
+
tbd
|
10
|
+
str
|
11
|
+
|
12
|
+
node_js '>= 8.8.1'
|
13
|
+
|
14
|
+
gem 'json'
|
15
|
+
npm :surge
|
16
|
+
env :surge
|
17
|
+
|
18
|
+
opt '--login EMAIL', 'Surge login (the email address you use with Surge)', required: true
|
19
|
+
opt '--token TOKEN', 'Surge login token (can be retrieved with `surge token`)', required: true, secret: true
|
20
|
+
opt '--domain NAME', 'Domain to publish to. Not required if the domain is set in the CNAME file in the project folder.'
|
21
|
+
opt '--project PATH', 'Path to project directory relative to repo root', default: '.'
|
22
|
+
|
23
|
+
cmds deploy: 'surge %{project} %{domain}'
|
24
|
+
|
25
|
+
msgs invalid_project: '%{project} is not a directory',
|
26
|
+
missing_domain: 'Please set the domain in .travis.yml or in a CNAME file in the project directory'
|
27
|
+
|
28
|
+
def login
|
29
|
+
ENV['SURGE_LOGIN'] ||= opts[:login]
|
30
|
+
ENV['SURGE_TOKEN'] ||= opts[:token]
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate
|
34
|
+
error :invalid_project if invalid_project?
|
35
|
+
error :missing_domain if missing_domain?
|
36
|
+
end
|
37
|
+
|
38
|
+
def deploy
|
39
|
+
shell :deploy
|
40
|
+
end
|
41
|
+
|
42
|
+
def invalid_project?
|
43
|
+
!File.directory?(project)
|
44
|
+
end
|
45
|
+
|
46
|
+
def missing_domain?
|
47
|
+
!domain && !File.exist?("#{project}/CNAME")
|
48
|
+
end
|
49
|
+
|
50
|
+
def project
|
51
|
+
expand(super, build_dir)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'dpl/version'
|
2
|
+
require 'net/http'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module Dpl
|
6
|
+
module Providers
|
7
|
+
class Testfairy < Provider
|
8
|
+
status :alpha
|
9
|
+
|
10
|
+
full_name 'TestFairy'
|
11
|
+
|
12
|
+
description sq(<<-str)
|
13
|
+
tbd
|
14
|
+
str
|
15
|
+
|
16
|
+
gem 'json'
|
17
|
+
gem 'multipart-post', '~> 2.0.0', require: 'net/http/post/multipart'
|
18
|
+
|
19
|
+
opt '--api_key KEY', 'TestFairy API key', required: true, secret: true
|
20
|
+
opt '--app_file FILE', 'Path to the app file that will be generated after the build (APK/IPA)', required: true
|
21
|
+
opt '--symbols_file FILE', 'Path to the symbols file'
|
22
|
+
opt '--testers_groups GROUPS', 'Tester groups to be notified about this build', example: 'e.g. group1,group1'
|
23
|
+
opt '--notify', 'Send an email with a changelog to your users'
|
24
|
+
opt '--auto_update', 'Automaticall upgrade all the previous installations of this app this version'
|
25
|
+
opt '--advanced_options OPTS', 'Comma_separated list of advanced options', example: 'option1,option2'
|
26
|
+
|
27
|
+
URL = 'https://upload.testfairy.com/api/upload'
|
28
|
+
UA = "Travis CI dpl version=#{Dpl::VERSION}"
|
29
|
+
|
30
|
+
msgs deploy: 'Uploading to TestFairy: %s',
|
31
|
+
done: 'Done. Check your build at %s'
|
32
|
+
|
33
|
+
def deploy
|
34
|
+
info :deploy, pretty_print(params)
|
35
|
+
body = JSON.parse(http.request(request).body)
|
36
|
+
error body['message'] if body['status'] == 'fail'
|
37
|
+
info :done, body['build_url']
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def params
|
43
|
+
@params ||= compact(
|
44
|
+
'api_key': api_key,
|
45
|
+
'apk_file': file(app_file),
|
46
|
+
'symbols_file': file(symbols_file),
|
47
|
+
'testers-groups': testers_groups,
|
48
|
+
'notify': bool(notify),
|
49
|
+
'auto-update': bool(auto_update),
|
50
|
+
'advanced-options': advanced_options,
|
51
|
+
'changelog': changelog
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def changelog
|
56
|
+
git_log "--pretty=oneline --abbrev-commit #{commits}" if commits
|
57
|
+
end
|
58
|
+
|
59
|
+
def commits
|
60
|
+
ENV['TRAVIS_COMMIT_RANGE']
|
61
|
+
end
|
62
|
+
|
63
|
+
def request
|
64
|
+
Net::HTTP::Post::Multipart.new(uri.path, params, 'User-Agent' => UA)
|
65
|
+
end
|
66
|
+
|
67
|
+
def http
|
68
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
def uri
|
72
|
+
@uri ||= URI.parse(URL)
|
73
|
+
end
|
74
|
+
|
75
|
+
def file(path)
|
76
|
+
UploadIO.new(path, '', File.basename(path)) if path
|
77
|
+
end
|
78
|
+
|
79
|
+
def bool(obj)
|
80
|
+
obj ? 'on' : 'off' unless obj.nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
def pretty_print(params)
|
84
|
+
params = params.map do |key, value|
|
85
|
+
value = obfuscate(value) if key == :api_key
|
86
|
+
value = value.path if value.respond_to?(:path)
|
87
|
+
[key, value]
|
88
|
+
end
|
89
|
+
JSON.pretty_generate(params.to_h)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Dpl
|
2
|
+
module Providers
|
3
|
+
class Transifex < Provider
|
4
|
+
status :alpha
|
5
|
+
|
6
|
+
description sq(<<-str)
|
7
|
+
tbd
|
8
|
+
str
|
9
|
+
|
10
|
+
python '>= 2.7', '!= 3.0', '!= 3.1', '!= 3.2', '!= 3.3', '< 3.8'
|
11
|
+
|
12
|
+
required :api_token, [:username, :password]
|
13
|
+
|
14
|
+
opt '--api_token TOKEN', 'Transifex API token', secret: true
|
15
|
+
opt '--username NAME', 'Transifex username'
|
16
|
+
opt '--password PASS', 'Transifex password', secret: true
|
17
|
+
opt '--hostname NAME', 'Transifex hostname', default: 'www.transifex.com'
|
18
|
+
opt '--cli_version VER', 'CLI version to install', default: '>=0.11'
|
19
|
+
|
20
|
+
cmds status: 'tx status',
|
21
|
+
push: 'tx push --source --no-interactive'
|
22
|
+
|
23
|
+
msgs login: 'Writing ~/.transifexrc (user: %{username}, password: %{password})'
|
24
|
+
errs push: 'Failure pushing to Transifex'
|
25
|
+
|
26
|
+
RC = sq(<<-rc)
|
27
|
+
[%{url}]
|
28
|
+
hostname = %{url}
|
29
|
+
username = %{username}
|
30
|
+
password = %{password}
|
31
|
+
rc
|
32
|
+
|
33
|
+
def install
|
34
|
+
pip_install 'transifex-client', 'tx', cli_version
|
35
|
+
end
|
36
|
+
|
37
|
+
def login
|
38
|
+
info :login
|
39
|
+
write_rc
|
40
|
+
shell :status
|
41
|
+
end
|
42
|
+
|
43
|
+
def deploy
|
44
|
+
shell :push, retry: true
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def write_rc
|
50
|
+
write_file '~/.transifexrc', interpolate(RC, opts, secure: true)
|
51
|
+
end
|
52
|
+
|
53
|
+
def username
|
54
|
+
super || 'api'
|
55
|
+
end
|
56
|
+
|
57
|
+
def password
|
58
|
+
super || api_token
|
59
|
+
end
|
60
|
+
|
61
|
+
def url
|
62
|
+
hostname.start_with?('https://') ? hostname : "https://#{hostname}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Silences "Struct::Tms is deprecated" warnings on Ruby 2.6.2 that would
|
2
|
+
# otherwise spam hundereds of warnings, on apparently every single const
|
3
|
+
# eager loaded (or something). The constant Tms is not used anywhere in
|
4
|
+
# the aws-sdk gem, so it seems safe to skip it.
|
5
|
+
#
|
6
|
+
# Maybe submit a patch to aws-sdk?
|
7
|
+
|
8
|
+
Aws::EagerLoader.class_eval do
|
9
|
+
def load(klass_or_module)
|
10
|
+
@loaded << klass_or_module
|
11
|
+
klass_or_module.constants.each do |const_name|
|
12
|
+
next if const_name == :Tms
|
13
|
+
path = klass_or_module.autoload?(const_name)
|
14
|
+
begin
|
15
|
+
require(path) if path
|
16
|
+
const = klass_or_module.const_get(const_name)
|
17
|
+
self.load(const) if Module === const && !@loaded.include?(const)
|
18
|
+
rescue LoadError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
self
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
|
3
|
+
module Dpl
|
4
|
+
module Support
|
5
|
+
class Gems < Struct.new(:glob, :opts)
|
6
|
+
def each(&block)
|
7
|
+
all.uniq.each(&block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def all
|
11
|
+
Dir[glob].sort.inject([]) do |gems, path|
|
12
|
+
next gems if except.any? { |str| path.include?(str) }
|
13
|
+
gems + Parse.new(File.read(path)).gems
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def except
|
18
|
+
@except ||= Array(opts[:except]).map(&:to_s)
|
19
|
+
end
|
20
|
+
|
21
|
+
def opts
|
22
|
+
super || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
class Parse < Struct.new(:code)
|
26
|
+
def gems
|
27
|
+
walk(*sexp).flatten.each_slice(3).to_a
|
28
|
+
end
|
29
|
+
|
30
|
+
def walk(key, *nodes)
|
31
|
+
case key
|
32
|
+
when :program
|
33
|
+
nodes[0].map { |node| walk(*node) }.compact
|
34
|
+
when :module
|
35
|
+
walk(*nodes[1])
|
36
|
+
when :class
|
37
|
+
walk(*nodes[2])
|
38
|
+
when :bodystmt
|
39
|
+
nodes[0].map { |node| walk(*node) }.compact
|
40
|
+
when :command
|
41
|
+
walk(*nodes[1]) if nodes[0][1] == 'gem'
|
42
|
+
when :args_add_block
|
43
|
+
args = nodes[0].map { |node| walk(*node) }
|
44
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
45
|
+
name, version = *args
|
46
|
+
[name, version, opts]
|
47
|
+
when :bare_assoc_hash
|
48
|
+
walk(*nodes[0][0])
|
49
|
+
when :assoc_new
|
50
|
+
[nodes.map { |node| walk(*node) }].to_h
|
51
|
+
when :@label
|
52
|
+
nodes.first.sub(':', '').to_sym
|
53
|
+
when :string_literal
|
54
|
+
walk(*nodes[0])
|
55
|
+
when :string_content
|
56
|
+
nodes[0][1]
|
57
|
+
# when :void_stmt
|
58
|
+
# else
|
59
|
+
# raise key.to_s
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def sexp
|
64
|
+
Ripper.sexp(code)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|