Class: Git::Trifle

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/git/trifle.rb,
lib/git/trifle/version.rb

Constant Summary collapse

STATUS_LIST =
[:changed, :added, :deleted, :untracked].freeze
DELEGATORS =

Needless to do more than this for the following methods Very neat BTW.

%W|
  add add_remote apply
  branch branches
  current_branch commit
  fetch
  log ls_files
  merge
  pull push
  reset remotes remove
|.
map(&:to_sym).
freeze
VERSION =
"0.0.1"

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Trifle

Returns a new instance of Trifle.



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/git/trifle.rb', line 41

def initialize(options={})
  @dressing = []

  if options.is_a? String
    cover options
  elsif options[:clone]
    clone options.merge!(remote: options[:clone])
  elsif options[:init]
    init options.merge!(path: options[:init])
  end
end

Instance Method Details

#alterations(options = {}) ⇒ Object



239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/git/trifle.rb', line 239

def alterations(options={})
  # which files have a status
  # represented as in status above
  if block_given?
    status(options[:status]).select { |t, files| files.any? }.each do |type, files|
      files.each do |file|
        yield type, file
      end
    end
  else
    status(options[:status]).select { |t, files| files.any? }
  end
end

#altered?Boolean

Returns:

  • (Boolean)


366
367
368
# File 'lib/git/trifle.rb', line 366

def altered?
  get_status != @status
end

#any_remote?Boolean

Potato Potato method, i love it

Returns:

  • (Boolean)


358
359
360
# File 'lib/git/trifle.rb', line 358

def any_remote?
  remotes.any?
end

#can_checkout?(name) ⇒ Boolean

do we have a remote branch or do we have at least one commit on this repo’

Returns:

  • (Boolean)


353
354
355
# File 'lib/git/trifle.rb', line 353

def can_checkout?(name)
  has_remote_branch?(name) || local_branches.any?
end

#can_cover?(path) ⇒ Boolean

Returns:

  • (Boolean)


314
315
316
317
318
# File 'lib/git/trifle.rb', line 314

def can_cover?(path)
  # is there any other way ?
  # dunno for now
  File.exists? File.join(path, '.git')
end

#checkout(name, options = {}) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/git/trifle.rb', line 110

def checkout(name, options={})
  # avoid crash when repo' was just init'ed
  return false unless can_checkout? name

  # 0 but true
  return true if name == current_branch

  # -b option on command line
  options.merge! new_branch: true unless name.nil? || has_branch?(name)

  # wipe all options to let git to the job and checkout
  # tracking branch. YKWIM ? then DWIM
  options = {} if has_remote_branch? name
  @layer.checkout name, options
end

#checkout_changed_filesObject



138
139
140
# File 'lib/git/trifle.rb', line 138

def checkout_changed_files
  checkout_files files_with_status(:changed)
end

#checkout_deleted_filesObject



134
135
136
# File 'lib/git/trifle.rb', line 134

def checkout_deleted_files
  checkout_files files_with_status(:deleted)
end

#checkout_files(files) ⇒ Object

i know, it exists in Git gem. But i prefer having here with my own checkout method as a pivotal point for all checkouts (as long as it is accurate)



129
130
131
132
# File 'lib/git/trifle.rb', line 129

def checkout_files(files)
  files = Array(files).select { |path| files_paths.include? path }
  checkout nil, files: files if files
end

#clone(options) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/git/trifle.rb', line 63

def clone(options)
  path, name = File.split options[:path]
  remote = options.delete :remote
  reset = options.delete :reset

  cook_layer do
    # Dunno why i have to do that, but that's a fact. Ain't workin' without...
    FileUtils.mkdir_p path

    @dressing << Proc.new { self.reset if commits.any? } if reset
    Git.clone remote, name, options.merge!(path: path)
  end
end

#commits(options = {}) ⇒ Object



163
164
165
166
167
168
169
170
# File 'lib/git/trifle.rb', line 163

def commits(options={})
  options[:branch] ||= current_branch

  # yeah, reverse !
  # Because it's only in the Bible that i understand
  # why the first ones will be the last ones.
  log.object(options[:branch]).map(&:sha).reverse rescue []
end

#cover(path, options = {}) ⇒ Object

hands on the handler



54
55
56
57
58
59
60
61
# File 'lib/git/trifle.rb', line 54

def cover(path, options={})
  reset = options.delete :reset

  cook_layer do
    @dressing << Proc.new { self.reset if commits.any? } if reset
    Git::Base.open path if can_cover? path
  end
end

#covers_anything?Boolean

Returns:

  • (Boolean)


362
363
364
# File 'lib/git/trifle.rb', line 362

def covers_anything?
  !!@layer
end

#create_branch(name, options = {}) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/git/trifle.rb', line 88

def create_branch(name, options={})
  # go to bed Captain, we don't need you here
  options[:track] = remote_branch_for(name) if options.delete :track_remote

  # mere delegation with options
  branch(name, options).create
end

#delete_branch(branch) ⇒ Object



96
97
98
99
100
101
# File 'lib/git/trifle.rb', line 96

def delete_branch(branch)
  # woodsman advice : dude, don't saw the branch you're on
  return if branch == current_branch
  # actual mere delegation
  branch(branch).delete
end

#diff(first, second) ⇒ Object

So far, only two commits diff is implemented



173
174
175
# File 'lib/git/trifle.rb', line 173

def diff(first, second)
  @layer.diff(first, second).to_s
end

#directoryObject



268
269
270
271
272
# File 'lib/git/trifle.rb', line 268

def directory
  # explanation here ?
  # Really ?
  @layer.dir.to_s
end

#file_was_ever_known?(path) ⇒ Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/git/trifle.rb', line 177

def file_was_ever_known?(path)
  log.path(path).any?
end

#file_with_status(file, s) ⇒ Object



264
265
266
# File 'lib/git/trifle.rb', line 264

def file_with_status(file, s)
  files_with_status(s).include? file
end

#files_pathsObject



278
279
280
281
# File 'lib/git/trifle.rb', line 278

def files_paths
  # for now, need only paths names
  ls_files.keys
end

#files_with_status(s) ⇒ Object



253
254
255
256
257
258
259
260
261
262
# File 'lib/git/trifle.rb', line 253

def files_with_status(s)
  # i like being specific
  if block_given?
    alterations(status: s) do |type, file|
      yield file
    end
  else
    alterations(status: s).values.flatten
  end
end

#full_path(path) ⇒ Object



274
275
276
# File 'lib/git/trifle.rb', line 274

def full_path(path)
  File.join directory, path
end

#get_status(type = nil) ⇒ Object



225
226
227
228
229
230
231
232
233
# File 'lib/git/trifle.rb', line 225

def get_status(type=nil)
  types = (type && STATUS_LIST.include?(type)) ? [type] : STATUS_LIST

  # Status as Hash of arrays, keys are statuses
  types.inject({}) do |s, type|
    # i.g layer.status.changed and keys only to get the filenames
    s.merge! type => @layer.status.send(type).keys
  end
end

#has_branch?(name) ⇒ Boolean

Returns:

  • (Boolean)


332
333
334
335
# File 'lib/git/trifle.rb', line 332

def has_branch?(name)
  # whether local or remote
  has_local_branch?(name) || has_remote_branch?(name)
end

#has_local_branch?(name) ⇒ Boolean

Returns:

  • (Boolean)


337
338
339
# File 'lib/git/trifle.rb', line 337

def has_local_branch?(name)
  local_branches.include? name
end

#has_remote_branch?(name) ⇒ Boolean

Returns:

  • (Boolean)


341
342
343
# File 'lib/git/trifle.rb', line 341

def has_remote_branch?(name)
  remote_branches.map { |b| b.split('/').last }.include? name
end

#has_updates?(branch = nil) ⇒ Boolean

Returns:

  • (Boolean)


320
321
322
323
324
325
326
327
328
329
330
# File 'lib/git/trifle.rb', line 320

def has_updates?(branch=nil)
  branch ||= current_branch
  fetch

  # do and return nothing unless... Well, you can read that
  # all by yourself
  return unless has_local_branch?(branch) && has_remote_branch?(branch)

  # potential difference between local and remote
  commits(branch: branch) != commits(branch: remote_branch_for(branch))
end

#init(options) ⇒ Object



77
78
79
80
81
82
83
84
85
86
# File 'lib/git/trifle.rb', line 77

def init(options)
  path = options.delete :path
  remote = options.delete :remote
  remote_name = options.delete(:remote_name) { 'origin' }

  cook_layer do
    @dressing << Proc.new { self.add_remote remote_name, remote } if remote
    Git.init path, options
  end
end

#initial_commitObject



283
284
285
286
287
288
# File 'lib/git/trifle.rb', line 283

def initial_commit
  # get the repo' initial commit
  # the trinary with master is probably useless
  branch = has_branch?('master') ? 'master' : local_branches.first
  commits(branch: branch).first
end

#local_branchesObject



181
182
183
184
# File 'lib/git/trifle.rb', line 181

def local_branches
  # sorry, what ?
  branches.local.map &:name
end

#local_remotes_only?Boolean

Returns:

  • (Boolean)


309
310
311
312
# File 'lib/git/trifle.rb', line 309

def local_remotes_only?
  # well... yeah, i like to make people laugh
  remotes.all? { |r| File.exists? r.url }
end

#push_branch(branch = nil) ⇒ Object



103
104
105
106
107
108
# File 'lib/git/trifle.rb', line 103

def push_branch(branch=nil)
  # we don't need Captain Obvious here
  # Rest Captain, greater tasks await you !
  branch ||= current_branch
  push remote_for(branch), branch
end

#push_file(file, options = {}) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/git/trifle.rb', line 142

def push_file(file, options={})
  # yeah yeah i allow to push on another branch in one line
  # not sure it's a good idea. We'll see...
  options[:branch] ||= current_branch
  options[:remote] ||= remote_for(options[:branch])

  # not sure of the option name. Well...
  options[:verb] ||= 'add'

  # not always a good idea to actually perform
  # a checkout here but i let checkout method know that
  checkout options[:branch]

  # add || rm && commit
  send options[:verb], file
  commit "#{options[:verb]} #{file} (brought to you by #{self.class.name})"

  # Run Forrest, run !
  push options[:remote], options[:branch]
end

#remote_branch_for(branch) ⇒ Object



202
203
204
205
206
207
208
# File 'lib/git/trifle.rb', line 202

def remote_branch_for(branch)
  # that one's even funnier
  remote_branches.
    map { |b| b.split '/' }. # returns a list of remote branch name elements
    map { |elements| "#{elements[-2]}/#{elements[-1]}" if elements.last == branch }. # list of nil or remote branch names
    compact.first
end

#remote_branch_only?(name) ⇒ Boolean

if i can, i’ll think of a more teenily tinily specific used-only-once method later on

Returns:

  • (Boolean)


347
348
349
# File 'lib/git/trifle.rb', line 347

def remote_branch_only?(name)
  has_remote_branch?(name) && !has_local_branch?(name)
end

#remote_branchesObject



186
187
188
189
# File 'lib/git/trifle.rb', line 186

def remote_branches
  # sorry, what now ?
  branches.remote.map &:name
end

#remote_for(branch) ⇒ Object



191
192
193
194
195
196
197
198
199
200
# File 'lib/git/trifle.rb', line 191

def remote_for(branch)
  # get out of here if i don't know you at all
  return unless has_branch? branch

  # ok you got me... I Perl'ed when i was younger
  remote_branches.
    map { |b| b.split '/' }. # returns a list of remote branch name elements
    map { |elements| elements[-2] if elements.last == branch }. # list of nil or remote names
    compact.first || remote_name
end

#remote_name(options = {}) ⇒ Object



215
216
217
218
# File 'lib/git/trifle.rb', line 215

def remote_name(options={})
  # yucky ? Maybe... But funny as well...
  remotes.select { |r| options[:url] ? r.url == options[:url] : true }.map(&:name).first
end

#remote_url(options = {}) ⇒ Object



210
211
212
213
# File 'lib/git/trifle.rb', line 210

def remote_url(options={})
  # yucky ? Maybe... But funny as well...
  remotes.select { |r| options[:name] ? r.name == options[:name] : true }.map(&:url).first
end

#reset_to_remote_head!Object



220
221
222
223
# File 'lib/git/trifle.rb', line 220

def reset_to_remote_head!
  fetch
  reset remote_branch_for(current_branch)
end

#status(*args) ⇒ Object



235
236
237
# File 'lib/git/trifle.rb', line 235

def status(*args)
  @status = get_status(*args)
end

#uncover!Object



290
291
292
# File 'lib/git/trifle.rb', line 290

def uncover!
  @layer = nil
end

#wipe_directory!Object



298
299
300
301
302
303
304
305
306
307
# File 'lib/git/trifle.rb', line 298

def wipe_directory!
  # not too clever way to do that
  # i remove directories but try to avoid
  # removing the repo'
  files_paths.each do |f|
    f = File.join directory, f
    d = File.dirname f
    FileUtils.rm_rf d == directory ? f : d
  end
end

#wipe_file(path) ⇒ Object



294
295
296
# File 'lib/git/trifle.rb', line 294

def wipe_file(path)
  FileUtils.rm_f full_path(path)
end