Added support for checking out a particular revision
authorJan Vrany <jan.vrany@fit.cvut.cz>
Fri, 04 Nov 2016 00:22:47 +0000
changeset 72 3e832d54a4af
parent 71 68c8cccbdec5
child 73 d2fd92cae180
Added support for checking out a particular revision ...or tag or bookmark. For now it is implemented only for Mercurial SCM. If revision is not specified, then bookmark `master` is checked out. If there's no such bookmark and branch has multiple heads, then error is thrown. If it has only one head, that one is checked out.
rakelib/hglib.rb
rakelib/rbspec.rb
rakelib/scm.rb
--- a/rakelib/hglib.rb	Thu Nov 03 22:27:02 2016 +0000
+++ b/rakelib/hglib.rb	Fri Nov 04 00:22:47 2016 +0000
@@ -203,6 +203,23 @@
       end
     end
 
+    # Return name of an active bookmark or nil if no bookmark
+    # is active
+    def bookmark() 
+      filename = File.join(@path, '.hg', 'bookmarks.current')
+      if File.exist? filename then
+        file = File.open(filename, "r")
+        begin
+          bookmark = file.read.chomp
+        ensure
+          file.close()
+        end
+        return bookmark
+      else
+        return nil
+      end
+    end
+
     # Return a hash "bookmark => revision" of all 
     # bookmarks. 
     def bookmarks(branch = nil)
@@ -216,7 +233,7 @@
       return bookmarks
     end
 
-    def pull(remote = 'default', user: nil, pass: nil, rev: nil)
+    def pull(remote = 'default', user: nil, pass: nil, rev: nil, bookmarks: [])
       authconf = []
       if pass != nil then
         if user == nil then
--- a/rakelib/rbspec.rb	Thu Nov 03 22:27:02 2016 +0000
+++ b/rakelib/rbspec.rb	Fri Nov 04 00:22:47 2016 +0000
@@ -333,7 +333,8 @@
 
     
     property :repository, :class => Symbol
-    property :branch
+    property :branch, :class => String
+    property :revision, :class => String
     property :link, :values => [ true, false ], :default => true
     property :test, :values => [ true, false ], :default => false
     property :coverage, :values => [ true, false ], :default => false
@@ -342,13 +343,13 @@
     property :checkout, :default => (Proc.new do | pkg |
                                      info "Checking out #{pkg.name}..."
                                      checkout pkg.repository, pkg.directory, 
-                                     :branch => pkg.branch, :package => pkg, :separator => pkg._separator
+                                     :branch => pkg.branch, :revision => pkg.revision, :package => pkg, :separator => pkg._separator
                                    end), :class => Proc
 
     property :update, :default => (Proc.new do | pkg |
                                    info "Updating #{pkg.name}..."
                                    update pkg.repository, pkg.directory, 
-                                   :branch => pkg.branch, :package => pkg, :separator => pkg._separator
+                                   :branch => pkg.branch, :revision => pkg.revision, :package => pkg, :separator => pkg._separator
                                  end), :class => Proc
 
     property :stc_flags, :default => '+optinline +optinline2 -optContext', :class => String    
--- a/rakelib/scm.rb	Thu Nov 03 22:27:02 2016 +0000
+++ b/rakelib/scm.rb	Fri Nov 04 00:22:47 2016 +0000
@@ -56,8 +56,10 @@
   end
 
   def self._update_hg(repository, directory, branch, root, **kwargs)
+    
     wc = root / directory
     separator = kwargs[:separator] || '.'
+    revision =  kwargs[:revision] 
     if directory != nil then      
       url = "#{repository.canonical}/#{directory.gsub('/', separator)}"
     end
@@ -79,7 +81,27 @@
       if paths['default'] != paths['canonical'] then
         hg.pull('canonical')
       end
-      hg.update()
+      # If revision is not specified, then look for an active bookmark
+      # and update to it. If no bookmark is active, then look for bookmark
+      # `master`. If it exist, then update to `master`. If it 
+      # does not, then update to tip or throw an error.
+      # The error is thrown if there's no bookmark `master` and
+      # branch has multiple heads since it's not clear which 
+      # head rev to use.
+      if not revision then
+        revision = hg.bookmark()
+        if not revision then
+          bookmarks = hg.bookmarks(branch)
+          if (bookmarks.has_key? 'master') then
+            revision = 'master'
+          else
+            if (hg.heads(branch).size > 1) then
+              raise CheckoutException.new("HG: Cannot checkout #{directory}: branch #{branch} has multiple heads but no bookmark named 'master'!")
+            end            
+          end          
+        end
+      end
+      hg.update(revision || branch)
     rescue Exception => ex 
       raise CheckoutException.new("HG: Cannot update #{wc}: #{ex.message}")
     end
@@ -152,7 +174,7 @@
 
   def self._checkout_hg(repository, directory, branch, root, **kwargs)    
     separator = kwargs[:separator] || '.'
-
+    revision =  kwargs[:revision] 
     hg = HG::Repository.init(root / directory)
     paths = { 'default' => "#{repository.upstream}/#{directory.gsub('/', separator)}",
               'canonical' => "#{repository.canonical}/#{directory.gsub('/', separator)}" }            
@@ -161,7 +183,6 @@
     end
 
     hg.paths = paths
-
     begin
       if repository.staging then
         hg.pull('staging')
@@ -170,7 +191,24 @@
       if paths['default'] != paths['canonical'] then
         hg.pull('canonical')
       end
-      hg.update(branch)
+      # If revision is not specified, then look for bookmark
+      # `master`. If it exist, then check out `master`. If it 
+      # does not, then checkout tip or throw an error.
+      # The error is thrown if there's no bookmark `master` and
+      # branch has multiple heads since it's not clear which 
+      # head rev to use.
+      if not revision then
+        bookmarks = hg.bookmarks(branch)
+        if (bookmarks.has_key? 'master') then
+          revision = 'master'
+        else
+          if (hg.heads(branch).size > 1) then
+            raise CheckoutException.new("HG: Cannot checkout #{directory}: branch #{branch} has multiple heads but no bookmark named 'master'!")
+          end            
+        end          
+      end
+
+      hg.update(revision || branch)
     #rescue Exception => e
     #  raise CheckoutException.new("HG: Cannot clone from #{url}: #{e.message}")
     end