Class: Autoproj::VCSDefinition

Inherits:
Object
  • Object
show all
Defined in:
lib/autoproj/vcs_definition.rb

Overview

Representation of a VCS definition contained in a source.yml file or in autoproj/manifest

Defined Under Namespace

Classes: HistoryEntry, RawEntry

Constant Summary collapse

ABSOLUTE_PATH_OR_URI =
/^([\w+]+:\/)?\/|^[:\w]+@|^(\w+@)?[\w.-]+:/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, url, vcs_options, from: nil, raw: [], history: []) ⇒ VCSDefinition

Returns a new instance of VCSDefinition.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/autoproj/vcs_definition.rb', line 36

def initialize(type, url, vcs_options, from: nil, raw: [], history: [])
    unless raw.respond_to?(:to_ary)
        raise ArgumentError, "wrong format for the raw field (#{raw.inspect})"
    end

    @type = type
    @url = url
    @options = vcs_options
    if type != "none" && type != "local" && !Autobuild.respond_to?(type)
        raise ConfigError.new, "version control #{type} is unknown to autoproj"
    end

    @history = history + [HistoryEntry.new(from, self)]
    @raw     = raw
end

Instance Attribute Details

#historyArray<HistoryEntry> (readonly)

This VCSDefinition history

i.e. the list of VCSDefinition objects that led to this one by means of calls to #update

Returns:



26
27
28
# File 'lib/autoproj/vcs_definition.rb', line 26

def history
  @history
end

#optionsHash (readonly)

The VCS options

Returns:

  • (Hash)


18
19
20
# File 'lib/autoproj/vcs_definition.rb', line 18

def options
  @options
end

#rawArray<RawEntry> (readonly)

The original spec in hash form

Returns:



31
32
33
# File 'lib/autoproj/vcs_definition.rb', line 31

def raw
  @raw
end

#typeSymbol (readonly)

The VCS type

Returns:

  • (Symbol)


8
9
10
# File 'lib/autoproj/vcs_definition.rb', line 8

def type
  @type
end

#urlString (readonly)

The VCS URL

Returns:

  • (String)


13
14
15
# File 'lib/autoproj/vcs_definition.rb', line 13

def url
  @url
end

Class Method Details

.from_raw(spec, from: nil, raw: [], history: []) ⇒ VCSDefinition

Converts a ‘raw’ VCS representation to a normalized hash.

The raw definition can have three forms:

* as a plain string, which is a relative/absolute path
* as a plain string, which is a vcs_type:url string
* as a hash

Returns:

Raises:

  • ArgumentError if the raw specification does not match an expected format



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/autoproj/vcs_definition.rb', line 204

def self.from_raw(spec, from: nil, raw: [], history: [])
    normalized_spec = normalize_vcs_hash(spec)
    unless (type = normalized_spec.delete(:type))
        raise ArgumentError,
              "the source specification #{raw_spec_to_s(spec)} normalizes "\
              "into #{raw_spec_to_s(normalized_spec)}, "\
              "which does not have a VCS type"
    end

    if !(url  = normalized_spec.delete(:url)) && type != "none"
        raise ArgumentError,
              "the source specification #{raw_spec_to_s(spec)} normalizes "\
              "into #{raw_spec_to_s(normalized_spec)}, "\
              "which does not have a URL. "\
              "Only VCS of type 'none' do not require one"
    end

    VCSDefinition.new(
        type, url, normalized_spec, from: from, history: history, raw: raw
    )
end

.noneObject

Create a null VCS object



53
54
55
# File 'lib/autoproj/vcs_definition.rb', line 53

def self.none
    from_raw({ type: "none" })
end

.normalize_vcs_hash(spec, base_dir: nil) ⇒ Object

Normalizes a VCS definition contained in a YAML file into a hash

It handles custom source handler expansion, as well as the bad habit of forgetting a ‘:’ at the end of a line:

- package_name
  branch: value

Raises:

  • ArgumentError if the given spec cannot be normalized



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/autoproj/vcs_definition.rb', line 120

def self.normalize_vcs_hash(spec, base_dir: nil)
    plain = Array.new
    filtered_spec = Hash.new

    if spec.respond_to?(:to_str)
        plain << spec
        spec = Hash.new
    else
        Array(spec).each do |key, value|
            keys = key.to_s.split(/\s+/)
            plain.concat(keys[0..-2])
            filtered_spec[keys[-1].to_sym] = value
        end
        spec = filtered_spec
    end

    if plain.size > 1
        raise ArgumentError, "invalid syntax"
    elsif plain.size == 1
        short_url = plain.first
        vcs, *url = short_url.split(":")

        # Check if VCS is a known version control system or source handler
        # shortcut. If it is not, look for a local directory called
        # short_url
        if Autobuild.respond_to?(vcs)
            spec.merge!(type: vcs, url: url.join(":"))
        elsif Autoproj.has_source_handler?(vcs)
            spec = Autoproj.call_source_handler(vcs, url.join(":"), spec)
        else
            source_dir =
                if Pathname.new(short_url).absolute?
                    File.expand_path(short_url)
                elsif base_dir
                    File.expand_path(short_url, base_dir)
                else
                    raise ArgumentError,
                          "VCS path '#{short_url}' is relative and no "\
                          "base_dir was given"
                end
            unless File.directory?(source_dir)
                raise ArgumentError,
                      "'#{short_url}' is neither a remote source "\
                      "specification, nor an existing local directory"
            end
            spec.merge!(type: "local", url: source_dir)
        end
    end

    spec, vcs_options = Kernel.filter_options spec, type: nil, url: nil
    spec.merge!(vcs_options)
    unless spec[:url]
        # Verify that none of the keys are source handlers. If it is the
        # case, convert
        filtered_spec = Hash.new
        spec.dup.each do |key, value|
            if Autoproj.has_source_handler?(key)
                spec.delete(key)
                spec = Autoproj.call_source_handler(key, value, spec)
                break
            end
        end
    end

    spec
end

.raw_spec_to_s(spec) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Converts a raw spec (a hash, really) into a nicely formatted string



190
191
192
# File 'lib/autoproj/vcs_definition.rb', line 190

def self.raw_spec_to_s(spec)
    "{ #{spec.sort_by(&:first).map { |k, v| "#{k}: #{v}" }.join(', ')} }"
end

.to_absolute_url(url, root_dir) ⇒ Object



254
255
256
257
# File 'lib/autoproj/vcs_definition.rb', line 254

def self.to_absolute_url(url, root_dir)
    url = File.expand_path(url, root_dir) if url && url !~ ABSOLUTE_PATH_OR_URI
    url
end

.update_raw_vcs_spec(old, new) ⇒ Object

Updates the VCS specification old by the information contained in new

Both old and new are supposed to be in hash form. It is assumed that old has already been normalized by a call to normalize_vcs_hash. new can be in “raw” form.



99
100
101
102
103
104
105
106
107
108
109
# File 'lib/autoproj/vcs_definition.rb', line 99

def self.update_raw_vcs_spec(old, new)
    new = normalize_vcs_hash(new)
    if new.has_key?(:type) && (old[:type] != new[:type])
        # The type changed. We replace the old definition by the new one
        # completely, and we make sure that the new definition is valid
        from_raw(new)
        new
    else
        old.merge(new)
    end
end

Instance Method Details

#==(other_vcs) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/autoproj/vcs_definition.rb', line 226

def ==(other_vcs)
    return false unless other_vcs.kind_of?(VCSDefinition)

    if local?
        other_vcs.local? && url == other_vcs.url
    elsif other_vcs.local?
        false
    elsif none?
        other_vcs.none?
    elsif other_vcs.none?
        false
    else
        this_importer = create_autobuild_importer
        other_importer = other_vcs.create_autobuild_importer
        this_importer.source_id == other_importer.source_id
    end
end

#create_autobuild_importerAutobuild::Importer?

Returns a properly configured instance of a subclass of Autobuild::Importer that match this VCS definition

Returns:

  • (Autobuild::Importer, nil)

    the autobuild importer



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/autoproj/vcs_definition.rb', line 278

def create_autobuild_importer
    return unless needs_import?

    importer = Autobuild.send(type, url, options)
    if importer.respond_to?(:declare_alternate_repository)
        history.each do |entry|
            package_set = entry.package_set
            vcs         = entry.vcs
            next if !package_set || package_set.main?

            importer.declare_alternate_repository(package_set.name, vcs.url, vcs.options)
        end
    end
    importer
end

#eql?(other_vcs) ⇒ Boolean

Returns:

  • (Boolean)


248
249
250
# File 'lib/autoproj/vcs_definition.rb', line 248

def eql?(other_vcs)
    to_hash == other_vcs.to_hash
end

#hashObject



244
245
246
# File 'lib/autoproj/vcs_definition.rb', line 244

def hash
    to_hash.hash
end

#local?Boolean

Whether this points to a local directory

Returns:

  • (Boolean)


63
64
65
# File 'lib/autoproj/vcs_definition.rb', line 63

def local?
    @type == "local"
end

#needs_import?Boolean

Whether the underlying package needs to be imported

Returns:

  • (Boolean)


260
261
262
# File 'lib/autoproj/vcs_definition.rb', line 260

def needs_import?
    type != "none" && type != "local"
end

#none?Boolean

Whether there is actually a version control definition

Returns:

  • (Boolean)


58
59
60
# File 'lib/autoproj/vcs_definition.rb', line 58

def none?
    @type == "none"
end

#overrides_keyObject



264
265
266
267
268
269
270
271
272
# File 'lib/autoproj/vcs_definition.rb', line 264

def overrides_key
    return if none?

    if local?
        "local:#{url}"
    else
        create_autobuild_importer.repository_id
    end
end

#to_hashHash

Converts self to a Hash description that could be passed to from_raw

Returns:

  • (Hash)


70
71
72
# File 'lib/autoproj/vcs_definition.rb', line 70

def to_hash
    Hash[type: type, url: url].merge(options)
end

#to_sObject

Returns a pretty representation of this VCS definition



295
296
297
298
299
300
301
302
303
304
305
# File 'lib/autoproj/vcs_definition.rb', line 295

def to_s
    if type == "none"
        "none"
    else
        desc = "#{type}:#{url}"
        unless options.empty?
            desc = "#{desc} #{options.to_a.sort_by { |key, _| key.to_s }.map { |key, value| "#{key}=#{value}" }.join(' ')}"
        end
        desc
    end
end

#update(spec, from: nil, raw: Array.new) ⇒ VCSDefinition

Update this VCS definition with new information / options and return the updated definition

Returns:



78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/autoproj/vcs_definition.rb', line 78

def update(spec, from: nil, raw: Array.new)
    new = self.class.normalize_vcs_hash(spec)
    new_raw = Array.new
    new_history = Array.new

    # If the type changed, we replace the old definition by the new one
    # completely. Otherwise, we append it to the current one
    if !new.has_key?(:type) || (type == new[:type])
        new = to_hash.merge(new)
        new_raw = self.raw + raw
        new_history = history
    end
    self.class.from_raw(new, from: from, history: new_history, raw: new_raw)
end