Class: Refs

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

Defined Under Namespace

Classes: Ref, SymRef

Constant Summary collapse

InvalidBranch =
Class.new(StandardError)
StaleValue =
Class.new(StandardError)
HEAD =
"HEAD"
ORIG_HEAD =
"ORIG_HEAD"
SYMREF =
/^ref: (.+)$/
REFS_DIR =
Pathname.new("refs")
HEADS_DIR =
REFS_DIR.join("heads")
REMOTES_DIR =
REFS_DIR.join("remotes")

Instance Method Summary collapse

Constructor Details

#initialize(pathname) ⇒ Refs

Returns a new instance of Refs.



47
48
49
50
51
52
# File 'lib/refs.rb', line 47

def initialize(pathname)
  @pathname     = pathname
  @refs_path    = @pathname.join(REFS_DIR)
  @heads_path   = @pathname.join(HEADS_DIR)
  @remotes_path = @pathname.join(REMOTES_DIR)
end

Instance Method Details

#compare_and_swap(name, old_oid, new_oid) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/refs.rb', line 83

def compare_and_swap(name, old_oid, new_oid)
  path = @pathname.join(name)

  update_ref_file(path, new_oid) do
    unless old_oid == read_symref(path)
      raise StaleValue, "value of #{ name } changed since last read"
    end
  end
end

#create_branch(branch_name, start_oid) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/refs.rb', line 93

def create_branch(branch_name, start_oid)
  path = @heads_path.join(branch_name)

  unless Revision.valid_ref?(branch_name)
    raise InvalidBranch, "'#{ branch_name }' is not a valid branch name."
  end

  if File.file?(path)
    raise InvalidBranch, "A branch named '#{ branch_name }' already exists."
  end

  update_ref_file(path, start_oid)
end

#current_ref(source = HEAD) ⇒ Object



124
125
126
127
128
129
130
131
# File 'lib/refs.rb', line 124

def current_ref(source = HEAD)
  ref = read_oid_or_symref(@pathname.join(source))

  case ref
  when SymRef   then current_ref(ref.path)
  when Ref, nil then SymRef.new(self, source)
  end
end

#delete_branch(branch_name) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/refs.rb', line 107

def delete_branch(branch_name)
  path = @heads_path.join(branch_name)

  lockfile = Lockfile.new(path)
  lockfile.hold_for_update

  oid = read_symref(path)
  raise InvalidBranch, "branch '#{ branch_name }' not found." unless oid

  File.unlink(path)
  delete_parent_directories(path)

  oid
ensure
  lockfile.rollback
end

#list_all_refsObject



133
134
135
# File 'lib/refs.rb', line 133

def list_all_refs
  [SymRef.new(self, HEAD)] + list_refs(@refs_path)
end

#list_branchesObject



137
138
139
# File 'lib/refs.rb', line 137

def list_branches
  list_refs(@heads_path)
end

#list_remotesObject



141
142
143
# File 'lib/refs.rb', line 141

def list_remotes
  list_refs(@remotes_path)
end

#long_name(ref) ⇒ Object

Raises:



166
167
168
169
170
171
172
# File 'lib/refs.rb', line 166

def long_name(ref)
  path = path_for_name(ref)
  return path.relative_path_from(@pathname).to_s if path

  raise InvalidBranch,
    "the requested upstream branch '#{ ref }' does not exist"
end

#read_headObject



54
55
56
# File 'lib/refs.rb', line 54

def read_head
  read_symref(@pathname.join(HEAD))
end

#read_ref(name) ⇒ Object



74
75
76
77
# File 'lib/refs.rb', line 74

def read_ref(name)
  path = path_for_name(name)
  path ? read_symref(path) : nil
end

#reverse_refsObject



145
146
147
148
149
150
151
152
153
154
# File 'lib/refs.rb', line 145

def reverse_refs
  table = Hash.new { |hash, key| hash[key] = [] }

  list_all_refs.each do |ref|
    oid = ref.read_oid
    table[oid].push(ref) if oid
  end

  table
end

#set_head(revision, oid) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/refs.rb', line 62

def set_head(revision, oid)
  head = @pathname.join(HEAD)
  path = @heads_path.join(revision)

  if File.file?(path)
    relative = path.relative_path_from(@pathname)
    update_ref_file(head, "ref: #{ relative }")
  else
    update_ref_file(head, oid)
  end
end

#short_name(path) ⇒ Object



156
157
158
159
160
161
162
163
164
# File 'lib/refs.rb', line 156

def short_name(path)
  path = @pathname.join(path)

  prefix = [@remotes_path, @heads_path, @pathname].find do |dir|
    path.dirname.ascend.any? { |parent| parent == dir }
  end

  path.relative_path_from(prefix).to_s
end

#update_head(oid) ⇒ Object



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

def update_head(oid)
  update_symref(@pathname.join(HEAD), oid)
end

#update_ref(name, oid) ⇒ Object



79
80
81
# File 'lib/refs.rb', line 79

def update_ref(name, oid)
  update_ref_file(@pathname.join(name), oid)
end