Rakefile for dealing with mercurial subrepos

Subrepositories are quite an important things if you have any bigger project, where you can extract some libraries, modules, parts or any other such things. We have chosen Mercurial for version control, because it distributed (svn suxx ass), easy to use, and have good cross-platform support. Until version 1.3 it did not have any support for subrepositories, now it has one. It is far from perfect, but still much better than nothing. And I am sure it will get better, or eventually great.

But for the time I have made quite simple Rakefile to help with subrepos. It works fine also with Mercurial versions less than 1.3. To use it you must have Ruby and gems: rake, term-ansicolor installed. Script assumes that you have subdirectories which are Mercurial repositiories and issues commands on each of them.

rake -T will give you list of available tasks:

  • hg - generic task. You can invoke it like: CMD=status rake hg and it will invoke CMD on every repository. In this case it will display status.
  • pull, push, status - does what the name says.
  • update - does pull -u.
  • rebase - does pull –rebase. You must have hgext.rebase= enabled for it to work.
  • tag - invoked rake tag name=0.1 will tag each repository with tag 0.1.
  • upto - invoked rake upto rev=0.2 will do hg up -r 0.2. It makes sense with branches and tags, not so much with revisions, because each subrepo have its own history ;-).
  • commit - if you have main repository, that contains all the others (as when you use Mercurial subrepo support) it will read commit messages from all the subrepos since last commit to the main repo and copy them into clipboard (works on a Mac only, I think).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
57
58
59
60
61
62
63
64
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
90
begin
  require 'term/ansicolor'
  class String
    include Term::ANSIColor
  end
rescue LoadError => e
  STDERR.puts "Please install gem term-ansicolor to use this rakefile."
  exit(1)
end

@repos = Dir["**/.hg"].map { |f| f.sub(/.hg$/, "") }
def on_repos(cmd)
  @repos.each do |project|
    begin
      puts "= #{project.red} (#{cmd.yellow})"
      system "cd #{project}; #{cmd}"
    rescue => e
      puts "Failed because: #{e}".red
    end
  end
end

desc "Invokes any hg command on every repo. Provide CMD=command env variable."
task :hg do
  if ENV['CMD'].nil?
    puts "Missing rev parameter"
  else
    on_repos("hg #{ENV['CMD']}")
  end
end

desc "Rebase"
task :rebase do
  on_repos("hg pull --rebase")
end

desc "Pull"
task :pull do
  on_repos("hg pull")
end

desc "Pull -u"
task :update do
  on_repos("hg pull -u")
end

desc "Status"
task :status do
  on_repos("hg status")
end

desc "Push"
task :push do
  on_repos("hg push")
end

desc "Tag repos. Provide name=tag_name param"
task :tag do |t, args|
  if args.name.nil?
    puts "Missing name parameter"
  else 
    on_repos("hg tag #{args.name}")
  end
end

desc "Update all repos to some revision. Provide rev=revision parameter."
task :upto do |t, args|
  if args.rev.nil?
    puts "Missing rev parameter"
  else
    on_repos("hg update -C #{args.name}")
  end
end

desc "Commits main repository and adds commits messages from every subrepo."
task :commit do
  require 'time'
  last_date = Time.parse(%x{hg tip --template '{date|isodate}'}) + 60
  date = last_date.strftime("%Y-%m-%d %H:%M")
  out = @repos.reject { |r| File.basename(r) == "itiner" }.map do |r| 
    log = %x{cd #{r} && hg log -d '>#{date}' --template="== {desc}\n"}.strip
    log.empty? ? nil : "= #{File.basename r}\n#{log}"
  end
  msg = out.compact.join("\n\n").strip
  # mac only?
  IO.popen('pbcopy', 'w') do |pipe|
    pipe.print(msg)
  end
  system "hg commit && hg push"
end

Comments
blog comments powered by Disqus
[Valid Atom 1.0]
Fork me on GitHub