Class: Babushka::Source

Inherits:
Object show all
Extended by:
LogHelpers, PathHelpers, ShellHelpers
Includes:
LogHelpers, PathHelpers
Defined in:
lib/babushka/source.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from LogHelpers

debug, deprecated!, log, log_block, log_error, log_ok, log_stderr, log_warn, removed!

Methods included from ShellHelpers

cmd_dir, current_username, log_shell, login_shell, raw_shell, shell, shell!, shell?, shell_cmd, sudo, which

Methods included from PathHelpers

cd, in_build_dir, in_download_dir

Constructor Details

#initialize(path, opts = {}) ⇒ Source

Returns a new instance of Source.

Raises:

  • (ArgumentError)


68
69
70
71
72
73
74
75
# File 'lib/babushka/source.rb', line 68

def initialize path, opts = {}
  raise ArgumentError, "Source.new options must be passed as a hash, not as #{opts.inspect}." unless opts.is_a?(Hash)
  @uri, @type = self.class.discover_uri_and_type(path)
  @name = (opts[:name] || self.class.default_name_for_uri(@uri)).to_s
  @deps = DepPool.new self
  @templates = DepPool.new self
  @loaded = @currently_loading = false
end

Instance Attribute Details

#depsObject (readonly)

Returns the value of attribute deps.



13
14
15
# File 'lib/babushka/source.rb', line 13

def deps
  @deps
end

#nameObject (readonly)

Returns the value of attribute name.



13
14
15
# File 'lib/babushka/source.rb', line 13

def name
  @name
end

#templatesObject (readonly)

Returns the value of attribute templates.



13
14
15
# File 'lib/babushka/source.rb', line 13

def templates
  @templates
end

#uriObject (readonly)

Returns the value of attribute uri.



13
14
15
# File 'lib/babushka/source.rb', line 13

def uri
  @uri
end

Class Method Details

.default_name_for_uri(uri) ⇒ Object



60
61
62
63
64
65
66
# File 'lib/babushka/source.rb', line 60

def self.default_name_for_uri uri
  if uri.nil?
    nil
  else
    File.basename(uri.to_s).chomp('.git')
  end
end

.default_remote_for(name) ⇒ Object



41
42
43
# File 'lib/babushka/source.rb', line 41

def self.default_remote_for name
  "https://github.com/#{name}/babushka-deps.git"
end

.discover_uri_and_type(path) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/babushka/source.rb', line 46

def self.discover_uri_and_type path
  if path.nil?
    [nil, :implicit]
  elsif path.to_s.sub(/^\w+:\/\//, '')[/^[^\/]+[@:]/]
    [path.to_s, :private]
  elsif path.to_s[/^git:\/\//]
    [path.to_s, :public]
  elsif path.to_s[/^\w+:\/\//]
    [path.to_s, :private]
  else
    [path.p, :local]
  end
end

.for_path(path) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/babushka/source.rb', line 25

def self.for_path path
  @sources ||= {}
  @sources[default_name_for_uri(path)] ||= begin
    remote = shell "git config remote.origin.url", :cd => path
    if remote.nil?
      Source.new path # local source
    else
      Source.new remote, :name => default_name_for_uri(path) # remote source with custom path
    end
  end
end

.for_remote(name) ⇒ Object



37
38
39
# File 'lib/babushka/source.rb', line 37

def self.for_remote name
  Source.new(default_remote_for(name), :name => name)
end

.presentObject



15
16
17
18
19
20
21
22
23
# File 'lib/babushka/source.rb', line 15

def self.present
  source_prefix.glob('*').map(&:p).select {|path|
    path.directory?
  }.map {|path|
    Source.for_path path
  }.select {|source|
    source.present?
  }
end

Instance Method Details

#==(other) ⇒ Object



144
145
146
147
148
149
# File 'lib/babushka/source.rb', line 144

def == other
  [:name, :uri, :type].all? {|method_name| other.respond_to? method_name } &&
  name == other.name &&
  uri == other.uri &&
  type == other.type
end

#add!Object



151
152
153
154
155
156
157
158
159
160
# File 'lib/babushka/source.rb', line 151

def add!
  if !cloneable?
    log "Nothing to add for #{name}."
  else
    raise_unless_addable!
    log_block "Adding #{name} from #{uri}" do
      update!
    end
  end
end

#clear!Object



162
163
164
165
# File 'lib/babushka/source.rb', line 162

def clear!
  deps.clear!
  templates.clear!
end

#cloneable?Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/babushka/source.rb', line 124

def cloneable?
  [:public, :private].include? type
end

#cloned?Boolean

Returns:

  • (Boolean)


128
129
130
# File 'lib/babushka/source.rb', line 128

def cloned?
  cloneable? && File.directory?(path / '.git')
end

#description_piecesObject



111
112
113
114
115
116
117
118
# File 'lib/babushka/source.rb', line 111

def description_pieces
  [
    name,
    uri.to_s,
    type,
    ("#{updated_at.round.xsecs} ago" if cloneable?)
  ]
end

#find(dep_spec) ⇒ Object



81
82
83
84
# File 'lib/babushka/source.rb', line 81

def find dep_spec
  load!
  deps.for(dep_spec)
end

#find_template(template_spec) ⇒ Object



86
87
88
89
# File 'lib/babushka/source.rb', line 86

def find_template template_spec
  load!
  templates.for(template_spec)
end

#implicit?Boolean

Returns:

  • (Boolean)


140
141
142
# File 'lib/babushka/source.rb', line 140

def implicit?
  type == :implicit
end

#inspectObject



233
234
235
# File 'lib/babushka/source.rb', line 233

def inspect
  "#<Source:#{object_id} '#{name}' (#{deps.count} dep#{'s' unless deps.count == 1})>"
end

#load!(should_update = false) ⇒ Object



167
168
169
170
171
172
173
174
# File 'lib/babushka/source.rb', line 167

def load! should_update = false
  unless @currently_loading
    @currently_loading = true
    update! if cloneable? && (!cloned? || should_update)
    load_deps! unless implicit? # implicit sources can't be loaded.
    @currently_loading = false
  end
end

#load_deps!Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/babushka/source.rb', line 176

def load_deps!
  unless @loaded
    path.p.glob('**/*.rb').each {|f|
      Base.sources.load_context :source => self, :path => f do
        load f
      end
    }
    debug "Loaded #{deps.count} deps from #{path}."
    @loaded = true
  end
rescue StandardError, SyntaxError => e
  clear!
  raise SourceLoadError.new(e.message).tap {|raised| raised.set_backtrace(e.backtrace) }
end

#local?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'lib/babushka/source.rb', line 136

def local?
  type == :local
end

#pathObject



95
96
97
98
99
100
101
# File 'lib/babushka/source.rb', line 95

def path
  @path ||= if implicit? || local?
    @uri
  else
    prefix / name
  end
end

#prefixObject



91
92
93
# File 'lib/babushka/source.rb', line 91

def prefix
  self.class.source_prefix
end

#present?Boolean

Returns:

  • (Boolean)


132
133
134
# File 'lib/babushka/source.rb', line 132

def present?
  cloneable? ? cloned? : path.exists?
end

#remove!Object



213
214
215
# File 'lib/babushka/source.rb', line 213

def remove!
  !cloneable? || !path.exists? || path.rm
end

#repoObject



103
104
105
# File 'lib/babushka/source.rb', line 103

def repo
  @repo ||= GitRepo.new(path) if cloneable?
end

#typeObject



120
121
122
# File 'lib/babushka/source.rb', line 120

def type
  @type
end

#update!Object



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/babushka/source.rb', line 191

def update!
  if @updated
    debug "Already pulled #{name} (#{uri}) this session."
    true
  elsif @updated == false
    debug "Not updating #{name} (#{uri}) - it's offline."
  elsif Base.sources.local_only?
    debug "Not pulling #{name} (#{uri}) - in local-only mode."
    true
  elsif repo.exists? && repo.dirty?
    log "Not updating #{name} (#{path}) because there are local changes."
  elsif repo.exists? && repo.ahead?
    @updated = false # So the ahead? check doesn't run again, for when there's no network.
    log "Not updating #{name} (#{path}) because it's ahead of origin."
  else
    GitHelpers.git(uri, :to => path, :log => true).tap {|result|
      log "Marking #{uri} as offline for this run." unless result
      @updated = result || false
    }
  end
end

#updated_atObject



107
108
109
# File 'lib/babushka/source.rb', line 107

def updated_at
  Time.now - File.mtime(path)
end

#uri_matches?(path) ⇒ Boolean

Returns:

  • (Boolean)


77
78
79
# File 'lib/babushka/source.rb', line 77

def uri_matches? path
  self.class.discover_uri_and_type(path).first == uri
end