Class: ScmWorkspace

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

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.0.2"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of ScmWorkspace.



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

def initialize(config, options = {})
  @root = config[:workspace]
  @logger = options[:logger]
end

Instance Attribute Details

#loggerObject



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

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

#rootObject (readonly)

Returns the value of attribute root.



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

def root
  @root
end

Class Method Details

.guess_scm_type(url) ⇒ Object



297
298
299
300
301
302
303
# File 'lib/scm_workspace.rb', line 297

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



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

def branch_names
  return nil unless configured?
  case scm_type
  when :git then
    result = git.branches.remote.map(&:full).map{|path| path.sub(/\Aremotes\/origin\//, '')}
    result.delete_if{|name| name =~ /\AHEAD ->/}
    result
  when :svn then
    git.branches.remote.map(&:full).map{|path| path.sub(/\Aremotes\//, '')}
  end
end

#checkout(branch_name) ⇒ Object



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

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

#clearObject



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

def clear
  FileUtils.remove_entry_secure(repo_dir) if Dir.exist?(repo_dir)
  FileUtils.rm(options_path) if File.exist?(options_path)
end

#cleared?Boolean

Returns:

  • (Boolean)


207
208
209
# File 'lib/scm_workspace.rb', line 207

def cleared?
  !configured?
end

#configure(url) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/scm_workspace.rb', line 29

def configure(url)
  raise "#{repo_dir} is not empty. You must clear it" if configured?
  FileUtils.mkdir_p(root)
  url, opt = url.split(/\s+/, 2)
  scm_type = self.class.guess_scm_type(url)
  options = opt ? parse_options(opt, scm_type) : {}
  options['url'] = url
  save_options(options)
  case scm_type
  when :git then
    logger.info("*" * 100)
    logger.info("SCM configure")
    puts_info "git clone #{url} #{repo_dir}"
    require 'git'
    @git = Git.clone(url, repo_dir)
  when :svn then
    Dir.chdir(@root) do
      cmd = "git svn clone #{url} #{repo_dir} #{opt} > /dev/null 2>&1"
      logger.info("*" * 100)
      logger.info("SCM configure")
      puts_info "cd #{@root} && " + cmd
      system(cmd)
    end
    @git = nil
  else
    raise "Unknown SCM type: #{url}"
  end
end

#configured?Boolean

Returns:

  • (Boolean)


203
204
205
# File 'lib/scm_workspace.rb', line 203

def configured?
  Dir.exist?(repo_dir)
end

#current_branch_nameObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/scm_workspace.rb', line 169

def current_branch_name
  return nil unless configured?
  case scm_type
  when :git then
    logger.info("-" * 100)
    r = git.log.first.name
    logger.info("current_branch_name: #{r.inspect}")
    r
  when :svn then
    info = svn_info
    r = info[:url].sub(info[:repository_root], '')
    r.sub!(/\A\//, '')
    if branch_prefix = load_options['branches']
      r.sub!(branch_prefix + "/", '')
    end
    r
  end
end

#current_commit_keyObject



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/scm_workspace.rb', line 127

def current_commit_key
  return nil unless configured?
  result = git.log.first.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_tag_namesObject



188
189
190
191
192
# File 'lib/scm_workspace.rb', line 188

def current_tag_names
  return nil unless configured?
  log = git.log.first
  git.tags.select{|b| b.log.first.sha == log.sha}.map(&:name)
end

#fetchObject



85
86
87
88
89
90
91
92
93
# File 'lib/scm_workspace.rb', line 85

def fetch
  case scm_type
  when :git then
    logger.info("-" * 100)
    puts_info("git fetch origin")
    git.fetch("origin")
  when :svn then in_repo_dir{ system("git svn fetch") }
  end
end

#gitObject



211
212
213
214
# File 'lib/scm_workspace.rb', line 211

def git
  require 'git'
  @git ||= Git.open(repo_dir, log: logger)
end

#git_repo?Boolean

Returns:

  • (Boolean)


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

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

#in_repo_dirObject



289
290
291
292
293
# File 'lib/scm_workspace.rb', line 289

def in_repo_dir
  Dir.chdir(repo_dir) do
    return yield
  end
end

#load_optionsObject Also known as: options



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

def load_options
  return {} unless File.readable?(options_path)
  YAML.load_file(options_path)
end

#options_pathObject



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

def options_path
  File.join(@root, "options.yml")
end

#parse_options(opt, scm_type) ⇒ Object



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

def parse_options(opt, scm_type)
  # "-T trunk --branches branches --tags tags -hoge --on" という文字列を
  #   [["-T", "trunk"], ["--branches", "branches"], ["--tags", "tags"], ["-hoge", nil], ["--on", nil]]
  # という風に分割します
  key_values = opt.scan(/(-[^\s]+)(?:\=|\s+)?([^-][^\s]+)?/)
  result = key_values.each_with_object({}){|(k,v), d| d[k.sub(/\A-{1,2}/, '').gsub(/-/, '_')] = v }
  CONFIGURE_OPTIONS[scm_type].each do |short_key, long_key|
    if v = result.delete(short_key)
      result[long_key] = v
    end
  end
  result
end

#puts_info(msg) ⇒ Object



24
25
26
27
# File 'lib/scm_workspace.rb', line 24

def puts_info(msg)
  logger.info(msg)
  $stdout.puts(msg)
end

#repo_dirObject



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

def repo_dir
  File.join(@root, "workspace")
end

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



74
75
76
77
78
79
80
81
82
# File 'lib/scm_workspace.rb', line 74

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

#save_options(hash) ⇒ Object



253
254
255
256
257
# File 'lib/scm_workspace.rb', line 253

def save_options(hash)
  open(options_path, "w") do |f|
    YAML.dump(hash, f)
  end
end

#scm_typeObject



275
276
277
278
279
280
# File 'lib/scm_workspace.rb', line 275

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

#statusObject



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/scm_workspace.rb', line 95

def status
  case scm_type
  when :git then
    logger.info("-" * 100)
    puts_info("git status")
    status_text = 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
    current_sha = git.log.first.sha
    status_text = in_repo_dir{
      cmd = "git log --branches --oneline #{current_sha}.."
      puts_info cmd
      `#{cmd}`
    }
    lines = status_text.split(/\n/)
    if lines.empty?
      "everything is up-to-dated."
    else
      latest_sha = lines.first
      "There is/are #{lines.length} commits." + in_repo_dir{
        " current revision: " << `git svn find-rev #{current_sha}`.strip <<
        " latest revision: " << `git svn find-rev #{latest_sha}`.strip
      }
    end
  end
end

#svn_infoObject



282
283
284
285
286
287
# File 'lib/scm_workspace.rb', line 282

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

#svn_repo?Boolean

Returns:

  • (Boolean)


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

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

#tag_namesObject



156
157
158
159
# File 'lib/scm_workspace.rb', line 156

def tag_names
  return nil unless configured?
  git.tags.map(&:name).uniq
end

#urlObject



161
162
163
164
165
166
167
# File 'lib/scm_workspace.rb', line 161

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