vanagon 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/git/basic_submodules.rb +53 -0
- data/lib/vanagon/component.rb +19 -13
- data/lib/vanagon/component/dsl.rb +6 -5
- data/lib/vanagon/component/source.rb +80 -53
- data/lib/vanagon/component/source/git.rb +129 -20
- data/lib/vanagon/component/source/http.rb +41 -73
- data/lib/vanagon/component/source/local.rb +105 -62
- data/lib/vanagon/platform/deb.rb +8 -0
- data/lib/vanagon/platform/rpm.rb +4 -0
- data/lib/vanagon/project/dsl.rb +3 -1
- data/lib/vanagon/utilities.rb +11 -54
- data/spec/fixtures/files/fake_file_ext.7z +0 -0
- data/spec/fixtures/files/fake_file_ext.bz +0 -0
- data/spec/fixtures/files/fake_file_ext.bz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.cpio +0 -0
- data/spec/fixtures/files/fake_file_ext.gz +0 -0
- data/spec/fixtures/files/fake_file_ext.rar +0 -0
- data/spec/fixtures/files/fake_file_ext.tar +0 -0
- data/spec/fixtures/files/fake_file_ext.tar.bz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.tar.xz +0 -0
- data/spec/fixtures/files/fake_file_ext.tbz +0 -0
- data/spec/fixtures/files/fake_file_ext.tbz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.txz +0 -0
- data/spec/fixtures/files/fake_file_ext.xz +0 -0
- data/spec/fixtures/files/fake_file_ext.z +0 -0
- data/spec/lib/vanagon/component/source/git_spec.rb +25 -17
- data/spec/lib/vanagon/component/source/http_spec.rb +2 -24
- data/spec/lib/vanagon/component/source/{localsource_spec.rb → local_spec.rb} +8 -8
- data/spec/lib/vanagon/component/source_spec.rb +150 -67
- data/spec/lib/vanagon/platform_spec.rb +40 -21
- data/spec/lib/vanagon/project/dsl_spec.rb +28 -3
- data/spec/lib/vanagon/utilities_spec.rb +0 -44
- metadata +28 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b41f01dda75f8d40767ea3c7e290cf11462ff94
|
4
|
+
data.tar.gz: 7c9b7ce98ff34e60371dbf087366cb0fd488c53d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dda1a3fde0dfb600e38da84061bfd3f006b4f8a199e04900d067a4a96408affb102e916622d88b8fa0e04f6773f686bf5e2ef13aef108c5560d2c42e009df54
|
7
|
+
data.tar.gz: 4263fedb95452fefc118f7a199d70756455cb02c0fadd1c36b9ad630cdfd8d67d647c7a358c683295ca5cc0d2c53f2eca1a5a1ee4efde71b9d91f02a864118f5
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module BasicSubmodulePrimitives
|
4
|
+
# Extend Git::Lib to support shotgunning submodules. This command
|
5
|
+
# is not smart, and it has very poor support for submodule options.
|
6
|
+
# For example, you can't pass any arguments to the handful of submodule
|
7
|
+
# options that accept them (like --depth). We may extend it later,
|
8
|
+
# but for rev. 0001, simply initializing them will suffice
|
9
|
+
def update_submodules(**options)
|
10
|
+
arr_opts = ['update']
|
11
|
+
options.each_pair do |k, v|
|
12
|
+
arr_opts << "--#{k}" if v
|
13
|
+
end
|
14
|
+
Dir.chdir(@git_work_dir) do
|
15
|
+
command('submodule', arr_opts)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module BasicSubmodules
|
21
|
+
# @example Initialize all git submodules
|
22
|
+
# >> repo = Git.clone("git@github.com:puppetlabs/facter.git", "facter", path: Dir.mktmpdir)
|
23
|
+
# => <Git::Base>
|
24
|
+
# >> repo.checkout "3.1.3
|
25
|
+
# => <String>
|
26
|
+
# >> repo.update_submodules(init: true)
|
27
|
+
# => <String>
|
28
|
+
# @param [Hash] options any options to pass to `git submodule update`
|
29
|
+
# @option options [Boolean] :init whether to initialize submodules when updating them
|
30
|
+
# @option options [Boolean] :use the submodule's remote-tracking branch instead of superproject's SHA1 sum
|
31
|
+
# @option options [Boolean] :no-fetch don't fetch new objects from the remote site.
|
32
|
+
# @option options [Boolean] :force remove submodule's working tree even if modified
|
33
|
+
# @option options [Boolean] :checkout checkout submodules in detached HEAD state
|
34
|
+
# @option options [Boolean] :merge merge recorded commit for submodule into the current branch of the submodule
|
35
|
+
# @option options [Boolean] :rebase rebase current branch of submodule onto the commit recorded in the superproject
|
36
|
+
# @option options [Boolean] :recursive recurse into nested submodules
|
37
|
+
# @return options [String] any output produced by `git` when submodules are initialized
|
38
|
+
def update_submodules(**options)
|
39
|
+
self.lib.update_submodules(options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Git
|
44
|
+
class Lib
|
45
|
+
include BasicSubmodulePrimitives
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Git
|
50
|
+
class Base
|
51
|
+
include BasicSubmodules
|
52
|
+
end
|
53
|
+
end
|
data/lib/vanagon/component.rb
CHANGED
@@ -105,17 +105,20 @@ class Vanagon
|
|
105
105
|
# makefile template
|
106
106
|
#
|
107
107
|
# @param workdir [String] working directory to put the source into
|
108
|
-
def get_source(workdir)
|
109
|
-
|
110
|
-
|
111
|
-
@source.
|
112
|
-
|
113
|
-
|
114
|
-
@
|
115
|
-
@
|
108
|
+
def get_source(workdir) # rubocop:disable Metrics/AbcSize
|
109
|
+
opts = options.merge({ workdir: workdir })
|
110
|
+
if url
|
111
|
+
@source = Vanagon::Component::Source.source(url, opts)
|
112
|
+
source.fetch
|
113
|
+
source.verify
|
114
|
+
@extract_with = source.respond_to?(:extract) ? source.extract(platform.tar) : ':'
|
115
|
+
@cleanup_source = source.cleanup if source.respond_to?(:cleanup)
|
116
|
+
@dirname = source.dirname
|
116
117
|
|
117
118
|
# Git based sources probably won't set the version, so we load it if it hasn't been already set
|
118
|
-
|
119
|
+
if source.respond_to?(:version)
|
120
|
+
@version ||= source.version
|
121
|
+
end
|
119
122
|
else
|
120
123
|
warn "No source given for component '#{@name}'"
|
121
124
|
|
@@ -140,10 +143,13 @@ class Vanagon
|
|
140
143
|
#
|
141
144
|
# @param workdir [String] working directory to put the source into
|
142
145
|
def get_sources(workdir)
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
146
|
+
sources.each do |source|
|
147
|
+
src = Vanagon::Component::Source.source source.url,
|
148
|
+
workdir: workdir,
|
149
|
+
ref: source.ref,
|
150
|
+
sum: source.sum
|
151
|
+
src.fetch
|
152
|
+
src.verify
|
147
153
|
end
|
148
154
|
end
|
149
155
|
|
@@ -310,11 +310,12 @@ class Vanagon
|
|
310
310
|
|
311
311
|
# This will add a source to the project and put it in the workdir alongside the other sources
|
312
312
|
#
|
313
|
-
# @param
|
314
|
-
# @param
|
315
|
-
#
|
316
|
-
|
317
|
-
|
313
|
+
# @param uri [String] uri of the source
|
314
|
+
# @param [Hash] options optional keyword arguments used to instatiate a new source
|
315
|
+
# @option opts [String] :sum
|
316
|
+
# @option opts [String] :ref
|
317
|
+
def add_source(uri, **options)
|
318
|
+
@component.sources << OpenStruct.new(options.merge({ url: uri }))
|
318
319
|
end
|
319
320
|
|
320
321
|
# Adds a directory to the list of directories provided by the project, to be included in any packages of the project
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'fustigit'
|
1
2
|
require 'vanagon/component/source/http'
|
2
3
|
require 'vanagon/component/source/git'
|
3
4
|
require 'vanagon/component/source/local'
|
@@ -5,74 +6,100 @@ require 'vanagon/component/source/local'
|
|
5
6
|
class Vanagon
|
6
7
|
class Component
|
7
8
|
class Source
|
8
|
-
SUPPORTED_PROTOCOLS =
|
9
|
-
|
9
|
+
SUPPORTED_PROTOCOLS = %w(file http https git).freeze
|
10
|
+
@rewrite_rules = {}
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
class << self
|
13
|
+
attr_reader :rewrite_rules
|
14
|
+
|
15
|
+
def register_rewrite_rule(protocol, rule)
|
16
|
+
if rule.is_a?(String) || rule.is_a?(Proc)
|
17
|
+
if SUPPORTED_PROTOCOLS.include?(protocol)
|
18
|
+
@rewrite_rules[protocol] = rule
|
19
|
+
else
|
20
|
+
raise Vanagon::Error, "#{protocol} is not a supported protocol for rewriting"
|
21
|
+
end
|
15
22
|
else
|
16
|
-
raise Vanagon::Error, "
|
23
|
+
raise Vanagon::Error, "String or Proc is required as a rewrite_rule."
|
17
24
|
end
|
18
|
-
else
|
19
|
-
raise Vanagon::Error, "String or Proc is required as a rewrite_rule."
|
20
25
|
end
|
21
|
-
end
|
22
26
|
|
23
|
-
|
24
|
-
|
27
|
+
def rewrite(url, protocol)
|
28
|
+
# Vanagon did not originally distinguish between http and https
|
29
|
+
# when looking up rewrite rules; this is no longer true, but it
|
30
|
+
# means that we should try to preserve old, dumb behavior until
|
31
|
+
# the rewrite engine is removed.
|
32
|
+
return rewrite(url, "http") if protocol == "https"
|
25
33
|
|
26
|
-
|
27
|
-
if rule
|
28
|
-
|
29
|
-
|
30
|
-
|
34
|
+
rule = @rewrite_rules[protocol]
|
35
|
+
if rule
|
36
|
+
if rule.is_a?(Proc)
|
37
|
+
return proc_rewrite(rule, url)
|
38
|
+
elsif rule.is_a?(String)
|
39
|
+
return string_rewrite(rule, url)
|
40
|
+
end
|
31
41
|
end
|
42
|
+
|
43
|
+
return url
|
32
44
|
end
|
33
45
|
|
34
|
-
|
35
|
-
|
46
|
+
def proc_rewrite(rule, url)
|
47
|
+
if rule.arity == 1
|
48
|
+
rule.call(url)
|
49
|
+
else
|
50
|
+
raise Vanagon::Error, "Unable to use provided rewrite rule. Expected Proc with one argument, Proc has #{rule.arity} arguments"
|
51
|
+
end
|
52
|
+
end
|
36
53
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
54
|
+
def string_rewrite(rule, original_url)
|
55
|
+
url = original_url.to_s
|
56
|
+
target_match = url.match(/.*\/([^\/]*)$/)
|
57
|
+
if target_match
|
58
|
+
target = target_match[1]
|
59
|
+
return File.join(rule, target)
|
60
|
+
else
|
61
|
+
raise Vanagon::Error, "Unable to apply url rewrite to '#{url}', expected to find at least one '/' in the url."
|
62
|
+
end
|
42
63
|
end
|
43
|
-
end
|
44
64
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
return File.join(rule, target)
|
50
|
-
else
|
51
|
-
raise Vanagon::Error, "Unable to apply url rewrite to '#{url}', expected to find at least one '/' in the url."
|
65
|
+
def parse_and_rewrite(uri)
|
66
|
+
url = URI.parse(uri)
|
67
|
+
return url unless url.scheme
|
68
|
+
rewrite(url.to_s, url.scheme)
|
52
69
|
end
|
53
|
-
end
|
54
70
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
# Basic factory to hand back the correct {Vanagon::Component::Source} subtype to the component
|
72
|
+
#
|
73
|
+
# @param url [String] URI of the source file (includes git@... style links)
|
74
|
+
# @param options [Hash] hash of the options needed for the subtype
|
75
|
+
# @param workdir [String] working directory to fetch the source into
|
76
|
+
# @return [Vanagon::Component::Source] the correct subtype for the given source
|
77
|
+
def source(uri, **options) # rubocop:disable Metrics/AbcSize
|
78
|
+
# First we try git
|
79
|
+
if Vanagon::Component::Source::Git.valid_remote?(parse_and_rewrite(uri))
|
80
|
+
return Vanagon::Component::Source::Git.new parse_and_rewrite(uri),
|
81
|
+
sum: options[:sum],
|
82
|
+
ref: options[:ref],
|
83
|
+
workdir: options[:workdir]
|
84
|
+
end
|
85
|
+
|
86
|
+
# Then we try HTTP
|
87
|
+
if Vanagon::Component::Source::Http.valid_url?(parse_and_rewrite(uri))
|
88
|
+
return Vanagon::Component::Source::Http.new parse_and_rewrite(uri),
|
89
|
+
sum: options[:sum],
|
90
|
+
workdir: options[:workdir]
|
91
|
+
end
|
92
|
+
|
93
|
+
# Then we try local
|
94
|
+
if Vanagon::Component::Source::Local.valid_file?(uri)
|
95
|
+
return Vanagon::Component::Source::Local.new uri,
|
96
|
+
workdir: options[:workdir]
|
97
|
+
end
|
74
98
|
|
75
|
-
|
99
|
+
# Failing all of that, we give up
|
100
|
+
raise Vanagon::Error,
|
101
|
+
"Unknown file type: '#{uri}'; cannot continue"
|
102
|
+
end
|
76
103
|
end
|
77
104
|
end
|
78
105
|
end
|
@@ -1,39 +1,69 @@
|
|
1
1
|
require 'vanagon/utilities'
|
2
|
+
require 'vanagon/errors'
|
3
|
+
# This stupid library requires a capital 'E' in its name
|
4
|
+
# but it provides a wealth of useful constants
|
5
|
+
require 'English'
|
6
|
+
require 'fustigit'
|
7
|
+
require 'git/basic_submodules'
|
8
|
+
require 'logger'
|
2
9
|
|
3
10
|
class Vanagon
|
4
11
|
class Component
|
5
12
|
class Source
|
6
13
|
class Git
|
7
|
-
|
8
|
-
|
14
|
+
attr_accessor :url, :ref, :workdir
|
15
|
+
attr_reader :version, :default_options, :repo
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Attempt to connect to whatever URL is provided and
|
19
|
+
# return True or False depending on whether or not
|
20
|
+
# `git` thinks it's a valid Git repo.
|
21
|
+
#
|
22
|
+
# @return [Boolean] whether #url is a valid Git repo or not
|
23
|
+
def valid_remote?(url)
|
24
|
+
!!::Git.ls_remote(url)
|
25
|
+
rescue ::Git::GitExecuteError
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Default options used when cloning; this may expand
|
31
|
+
# or change over time.
|
32
|
+
def default_options
|
33
|
+
@default_options ||= { ref: "refs/heads/master" }
|
34
|
+
end
|
35
|
+
private :default_options
|
9
36
|
|
10
37
|
# Constructor for the Git source type
|
11
38
|
#
|
12
39
|
# @param url [String] url of git repo to use as source
|
13
40
|
# @param ref [String] ref to checkout from git repo
|
14
41
|
# @param workdir [String] working directory to clone into
|
15
|
-
def initialize(url,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@url = url
|
20
|
-
@ref = ref
|
42
|
+
def initialize(url, workdir:, **options)
|
43
|
+
opts = default_options.merge(options)
|
44
|
+
|
45
|
+
# Ensure that #url returns a URI object
|
46
|
+
@url = URI.parse(url.to_s)
|
47
|
+
@ref = opts[:ref]
|
21
48
|
@workdir = workdir
|
49
|
+
@ref_name, @ref_type, = @ref.split('/', 3).reverse
|
50
|
+
|
51
|
+
# We can test for Repo existence without cloning
|
52
|
+
raise Vanagon::InvalidRepo, "#{url} not a valid Git repo" unless valid_remote?
|
22
53
|
end
|
23
54
|
|
24
55
|
# Fetch the source. In this case, clone the repository into the workdir
|
25
56
|
# and check out the ref. Also sets the version if there is a git tag as
|
26
57
|
# a side effect.
|
27
58
|
def fetch
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
59
|
+
clone!
|
60
|
+
checkout!
|
61
|
+
version
|
62
|
+
update_submodules
|
63
|
+
end
|
64
|
+
|
65
|
+
def ref
|
66
|
+
@ref_name || @ref
|
37
67
|
end
|
38
68
|
|
39
69
|
# Return the correct incantation to cleanup the source directory for a given source
|
@@ -43,18 +73,97 @@ class Vanagon
|
|
43
73
|
"rm -rf #{dirname}"
|
44
74
|
end
|
45
75
|
|
46
|
-
# There is no md5 to manually verify here, so
|
76
|
+
# There is no md5 to manually verify here, so this is a noop.
|
47
77
|
def verify
|
48
|
-
# nothing to do here, so just return
|
78
|
+
# nothing to do here, so just tell users that and return
|
79
|
+
puts "Nothing to verify for '#{dirname}' (using Git reference '#{ref}')"
|
49
80
|
end
|
50
81
|
|
51
82
|
# The dirname to reference when building from the repo
|
52
83
|
#
|
53
84
|
# @return [String] the directory where the repo was cloned
|
54
85
|
def dirname
|
55
|
-
File.basename(
|
86
|
+
File.basename(url.path, ".git")
|
87
|
+
end
|
88
|
+
|
89
|
+
# Use `git describe` to lazy-load a version for this component
|
90
|
+
def version
|
91
|
+
@version ||= describe
|
92
|
+
end
|
93
|
+
|
94
|
+
# Perform a git clone of @url as a lazy-loaded
|
95
|
+
# accessor for @clone
|
96
|
+
def clone
|
97
|
+
@clone ||= ::Git.clone(url, dirname, path: workdir)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Attempt to connect to whatever URL is provided and
|
101
|
+
# return True or False depending on whether or not
|
102
|
+
# `git` thinks it's a valid Git repo.
|
103
|
+
#
|
104
|
+
# @return [Boolean] whether #url is a valid Git repo or not
|
105
|
+
def valid_remote?
|
106
|
+
self.class.valid_remote? url
|
107
|
+
end
|
108
|
+
private :valid_remote?
|
109
|
+
|
110
|
+
# Provide a list of remote refs (branches and tags)
|
111
|
+
def remote_refs
|
112
|
+
(remote['tags'].keys + remote['branches'].keys).uniq
|
113
|
+
end
|
114
|
+
private :remote_refs
|
115
|
+
|
116
|
+
# Provide a list of local refs (branches and tags)
|
117
|
+
def refs
|
118
|
+
(clone.tags.map(&:name) + clone.branches.map(&:name)).uniq
|
119
|
+
end
|
120
|
+
private :refs
|
121
|
+
|
122
|
+
# Clone a remote repo, make noise about it, and fail entirely
|
123
|
+
# if we're unable to retrieve the remote repo
|
124
|
+
def clone!
|
125
|
+
puts "Cloning Git repo '#{url}'"
|
126
|
+
puts "Successfully cloned '#{dirname}'" if clone
|
127
|
+
rescue Git::GitExecuteError
|
128
|
+
raise Vanagon::InvalidRepo, "Unable to clone from '#{url}'"
|
56
129
|
end
|
130
|
+
private :clone!
|
131
|
+
|
132
|
+
# Checkout desired ref/sha, make noise about it, and fail
|
133
|
+
# entirely if we're unable to checkout that given ref/sha
|
134
|
+
def checkout!
|
135
|
+
puts "Checking out '#{ref}'' from Git repo '#{dirname}'"
|
136
|
+
clone.checkout(ref)
|
137
|
+
rescue ::Git::GitExecuteError
|
138
|
+
raise Vanagon::CheckoutFailed, "unable to checkout #{ref} from '#{url}'"
|
139
|
+
end
|
140
|
+
private :checkout!
|
141
|
+
|
142
|
+
# Attempt to update submodules, and do not panic
|
143
|
+
# if there are no submodules to initialize
|
144
|
+
def update_submodules
|
145
|
+
puts "Attempting to update submodules for repo '#{dirname}'"
|
146
|
+
clone.update_submodules(init: true)
|
147
|
+
end
|
148
|
+
private :update_submodules
|
149
|
+
|
150
|
+
# Determines a version for the given directory based on the git describe
|
151
|
+
# for the repository
|
152
|
+
#
|
153
|
+
# @return [String] The version of the directory according to git describe
|
154
|
+
def describe
|
155
|
+
clone.describe(ref, tags: true)
|
156
|
+
rescue ::Git::GitExecuteError
|
157
|
+
warn "Directory '#{dirname}' cannot be versioned by Git. Maybe it hasn't been tagged yet?"
|
158
|
+
end
|
159
|
+
private :describe
|
57
160
|
end
|
58
161
|
end
|
59
162
|
end
|
163
|
+
|
164
|
+
class GitError < Error; end
|
165
|
+
# Raised when a URI is not a valid Source Control repo
|
166
|
+
class InvalidRepo < GitError; end
|
167
|
+
# Raised when checking out a given ref from a Git Repo fails
|
168
|
+
class CheckoutFailed < GitError; end
|
60
169
|
end
|