Class: ScmWorkspace

Inherits:
Object
  • Object
show all
Defined in:
lib/scm_workspace.rb,
lib/scm_workspace/version.rb

Defined Under Namespace

Classes: Error

Constant Summary collapse

CONFIGURE_OPTIONS =
{
  svn: {
    "A" => "authors_file",
    "b" => "branches",
    "m!" => "minimize_rul",
    "q+" => "quiet",
    "r" => "revision",
    "s" => "stdlayout",
    "t" => "tags",
    "T" => "trunk",
  },

  git: {
    'n' => 'no_checkout',
    'l' => 'local',
    's' => 'shared',
    'o' => 'origin',
    'b' => 'branch',
    'u' => 'upload_pack',
    'c' => 'config',
  }
}
VERSION =
"0.3.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, options = {}) ⇒ ScmWorkspace

Returns a new instance of ScmWorkspace.



21
22
23
24
25
26
# File 'lib/scm_workspace.rb', line 21

def initialize(config, options = {})
  @root = config[:workspace]
  @logger = options[:logger]
  @verbose = options[:verbose] || (ENV["VERBOSE"] =~ /true|yes|on/)
  @svn_branch_prefix = options[:svn_branch_prefix] || ENV["SVN_BRANCH_PREFIX"] || "branches"
end

Instance Attribute Details

#loggerObject



28
29
30
# File 'lib/scm_workspace.rb', line 28

def logger
  @logger ||= Tengine::Support::NullLogger.new
end

#rootObject (readonly)

Returns the value of attribute root.



17
18
19
# File 'lib/scm_workspace.rb', line 17

def root
  @root
end

#svn_branch_prefixObject

Returns the value of attribute svn_branch_prefix.



19
20
21
# File 'lib/scm_workspace.rb', line 19

def svn_branch_prefix
  @svn_branch_prefix
end

#verboseObject

Returns the value of attribute verbose.



20
21
22
# File 'lib/scm_workspace.rb', line 20

def verbose
  @verbose
end

Class Method Details

.guess_scm_type(url) ⇒ Object



326
327
328
329
330
331
332
# File 'lib/scm_workspace.rb', line 326

def guess_scm_type(url)
  case url
  when /\Agit:\/\//, /\Agit\@/, /\.git\Z/ then :git
  when /svn/ then :svn
  else nil
  end
end

Instance Method Details

#branch_namesObject



181
182
183
184
185
186
187
188
189
190
191
# File 'lib/scm_workspace.rb', line 181

def branch_names
  return nil unless configured?
  case scm_type
  when :git then
    result = system_at_root!("git branch -r").lines.map{|path| path.sub(/\A\s*origin\//, '').strip }
    result.delete_if{|name| name =~ /\AHEAD ->/}
    result
  when :svn then
    system_at_root!("git branch -r").lines.map{|path| path.strip }
  end
end

#checkout(branch_name) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/scm_workspace.rb', line 101

def checkout(branch_name)
  logger.info("-" * 100)
  system_at_root!("git checkout #{branch_name}")
  case scm_type
  when :git then system_at_root!("git reset --hard origin/#{branch_name}")
  end
end

#clearObject



91
92
93
94
95
96
97
98
99
# File 'lib/scm_workspace.rb', line 91

def clear
  return unless Dir.exist?(repo_dir)
  fileutils.chdir(repo_dir) do
    (Dir.glob("*") + Dir.glob(".*")).each do |d|
      next if d =~ /\A\.+\Z/
      fileutils.remove_entry_secure(d)
    end
  end
end

#cleared?Boolean

Returns:

  • (Boolean)


265
266
267
# File 'lib/scm_workspace.rb', line 265

def cleared?
  !configured?
end

#commit_infoObject



172
173
174
175
176
177
178
179
# File 'lib/scm_workspace.rb', line 172

def commit_info
  {
    "scm_type" => scm_type.to_s,
    "url" => url,
    "branch" => current_branch_name,
    "commit_key" => current_commit_key
  }
end

#configure(url) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/scm_workspace.rb', line 65

def configure(url)
  if configured?
    msg = "#{repo_dir} is not empty. You must clear it"
    msg << "\nls -la #{repo_dir}" << `ls -la #{repo_dir}` if verbose
    raise msg
  end
  url, opt = url.split(/\s+/, 2)
  scm_type = self.class.guess_scm_type(url)
  case scm_type
  when :git then
    logger.info("*" * 100)
    logger.info("SCM configure")
    system!("git clone #{url} #{repo_dir} #{opt}")
  when :svn then
    fileutils.chdir(@root) do
      cmd = "git svn clone #{url} #{repo_dir} #{opt}"
      cmd << " > /dev/null 2>&1" unless verbose
      logger.info("*" * 100)
      logger.info("SCM configure")
      system(cmd)
    end
  else
    raise "Unknown SCM type: #{url}"
  end
end

#configured?Boolean

Returns:

  • (Boolean)


261
262
263
# File 'lib/scm_workspace.rb', line 261

def configured?
  Dir.exist?(File.join(repo_dir, ".git"))
end

#contains?(obj) ⇒ Boolean

Returns:

  • (Boolean)


269
270
271
# File 'lib/scm_workspace.rb', line 269

def contains?(obj)
  !!system_at_root!("git show #{obj} --oneline --quiet") rescue false
end

#current_branch_nameObject



213
214
215
216
217
218
219
# File 'lib/scm_workspace.rb', line 213

def current_branch_name
  return nil unless configured?
  case scm_type
  when :git then git_current_branch_name
  when :svn then svn_current_branch_name
  end
end

#current_commit_keyObject



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/scm_workspace.rb', line 155

def current_commit_key
  return nil unless configured?
  result = current_sha
  case scm_type
  when :svn then
    rev = nil
    cnt = 0
    while rev.nil?
      rev = in_repo_dir{ `git svn find-rev #{result}`.strip }
      cnt += 1
      raise "failed to get svn revision for #{result}" if cnt > 10
    end
    result << ':' << rev
  end
  result
end

#current_shaObject



151
152
153
# File 'lib/scm_workspace.rb', line 151

def current_sha
  system_at_root!("git log -1").scan(/^commit ([0-9a-f]+)$/).flatten.first
end

#current_tag_namesObject



251
252
253
254
# File 'lib/scm_workspace.rb', line 251

def current_tag_names
  return nil unless configured?
  system_at_root!("git describe --tags #{current_sha}").lines.map(&:strip) rescue []
end

#fetchObject



118
119
120
121
122
123
124
# File 'lib/scm_workspace.rb', line 118

def fetch
  logger.info("-" * 100)
  case scm_type
  when :git then system_at_root!("git fetch origin")
  when :svn then system_at_root!("git svn fetch")
  end
end

#fileutilsObject



32
33
34
# File 'lib/scm_workspace.rb', line 32

def fileutils
  @fileutils ||= FileUtils.with_logger(logger)
end

#git_current_branch_name(dir = repo_dir) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/scm_workspace.rb', line 221

def git_current_branch_name(dir = repo_dir)
  return nil unless Dir.exist?(dir)
  fileutils.chdir(dir) do
    # http://qiita.com/sugyan/items/83e060e895fa8ef2038c
    result = `git symbolic-ref --short HEAD`.strip
    return result unless result.nil? || result.empty?
    result = `git status`.scan(/On branch\s*(.+)\s*$/).flatten.first
    return result unless result.nil? || result.empty?
    work = `git log --decorate -1`.scan(/^commit\s[0-9a-f]+\s\((.+)\)/).
      flatten.first.split(/,/).map(&:strip).reject{|s| s =~ /HEAD\Z/}
    r = work.select{|s| s =~ /origin\//}.first
    r ||= work.first
    result = r.sub(/\Aorigin\//, '')
    return result
  end
rescue => e
  # puts "[#{e.class}] #{e.message}"
  # puts "Dir.pwd: #{Dir.pwd}"
  # puts "git status\n" << `git status`
  raise e
end

#git_repo?Boolean

Returns:

  • (Boolean)


296
297
298
299
# File 'lib/scm_workspace.rb', line 296

def git_repo?
  return nil unless configured?
  !remotes.empty? rescue false
end

#in_rootObject Also known as: in_repo_dir



318
319
320
321
322
# File 'lib/scm_workspace.rb', line 318

def in_root
  fileutils.chdir(repo_dir) do
    return yield
  end
end

#remotesObject



193
194
195
196
197
198
# File 'lib/scm_workspace.rb', line 193

def remotes
  system_at_root!("git remote -v show").lines.each_with_object({}) do |line, d|
    name, url, other = line.strip.split(/[\t\s]+/, 3)
    d[name] = url
  end
end

#repo_dirObject



257
258
259
# File 'lib/scm_workspace.rb', line 257

def repo_dir
  @root
end

#reset_hard(tag) ⇒ Object Also known as: move



109
110
111
112
113
114
115
# File 'lib/scm_workspace.rb', line 109

def reset_hard(tag)
  logger.info("-" * 100)
  case scm_type
  when :git then system_at_root!("git reset --hard #{tag}")
  when :svn then raise "Illegal operation for svn"
  end
end

#scm_typeObject



306
307
308
309
310
311
# File 'lib/scm_workspace.rb', line 306

def scm_type
  return nil unless configured?
  return :git if git_repo?
  return :svn if svn_repo?
  nil
end

#statusObject



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/scm_workspace.rb', line 126

def status
  logger.info("-" * 100)
  case scm_type
  when :git then
    status_text = system_at_root!("git status") # in_repo_dir{ `git status` }
    value = status_text.scan(/Your branch is behind 'origin\/#{current_branch_name}' by (\d+\s+commits)/)
    if value && !value.empty?
      "There is/are #{value.flatten.join}"
    else
      "everything is up-to-dated."
    end
  when :svn then
    status_text = system_at_root!("git log --branches --oneline #{current_sha}..")
    lines = status_text.split(/\n/)
    if lines.empty?
      "everything is up-to-dated."
    else
      latest_sha = lines.first
      "There is/are #{lines.length} commits." <<
        " current revision: " << system_at_root!("git svn find-rev #{current_sha}").strip <<
        " latest revision: "  << system_at_root!("git svn find-rev #{latest_sha}").strip
    end
  end
end

#svn_current_branch_nameObject



243
244
245
246
247
248
249
# File 'lib/scm_workspace.rb', line 243

def svn_current_branch_name
  info = svn_info
  r = info[:url].sub(info[:repository_root], '')
  r.sub!(/\A\//, '')
  r.sub!(svn_branch_prefix + "/", '')
  r
end

#svn_infoObject



313
314
315
316
# File 'lib/scm_workspace.rb', line 313

def svn_info
  txt = system_at_root!("git svn info")
  return txt.scan(/^(.+?): (.*)$/).each_with_object({}){|(k,v), d| d[k.downcase.gsub(/\s/, '_').to_sym] = v }
end

#svn_repo?Boolean

Returns:

  • (Boolean)


301
302
303
304
# File 'lib/scm_workspace.rb', line 301

def svn_repo?
  return nil unless configured?
  Dir.exist?(File.join(repo_dir, '.git', 'svn'))
end

#system!(cmd) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/scm_workspace.rb', line 36

def system!(cmd)
  logger.info("executing: #{cmd}")
  buf = []
  IO.popen("#{cmd} 2>&1") do |io|
    while line = io.gets
      # puts line
      buf << line
    end
  end

  if $?.exitstatus == 0
    msg = "\e[33mSUCCESS: %s\e[0m" % cmd
    r = buf.join
    msg << "\n" << r.strip if verbose
    logger.info(msg)
    return r
  else
    msg = "\e[31mFAILURE: %s\n%s\e[0m" % [cmd, buf.join.strip]
    logger.error(msg)
    raise Error, msg
  end
end

#system_at_root!(cmd) ⇒ Object



59
60
61
62
63
# File 'lib/scm_workspace.rb', line 59

def system_at_root!(cmd)
  fileutils.chdir(root) do
    return system!(cmd)
  end
end

#tag_namesObject



200
201
202
203
# File 'lib/scm_workspace.rb', line 200

def tag_names
  return nil unless configured?
  system_at_root!("git tag").lines.map{|path| path.strip.strip }
end

#urlObject



205
206
207
208
209
210
211
# File 'lib/scm_workspace.rb', line 205

def url
  return nil unless configured?
  case scm_type
  when :git then remotes["origin"]
  when :svn then svn_info[:repository_root]
  end
end