Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!
Showing posts with label subversion. Show all posts
Showing posts with label subversion. Show all posts

Monday, April 19, 2010

Setting up committer access Git for Tapestry 5

Given the problems I'm having, I decided to set up a new local Git repository for futher work. Here's how to do it:

$ git clone git://git.apache.org/tapestry5.git

This sets up a new working folder, tapestry5. It takes it a while to download the necessary Git repository objects.

$ cd tapestry5
$ curl http://git.apache.org/authors.txt -o .git/authors.txt
$ git config svn.authorsfile .git/authors.txt

This fetches the current list of authors so that proper names appear in various Git reports, then configures Git to make use of the file.

$ git svn init --prefix=origin/ --trunk=trunk https://svn.apache.org/repos/asf/tapestry/tapestry5

This tells Git where to sync from and to.

$ git svn rebase

And that finishes things up, ensuring that you have all the most recent revisions.

From here on in, the two commands you need the most are git svn rebase (to pull in repository changes) and git svn dcommit (to push deltas back to Subversion). You should always rebase before a dcommit.

Perhaps that's not quite complete; I generally create local Git topic branches; so I start my work with git co -Blocal to create (or overwrite) my local branch, do my work there as a series of commits, then: git co trunk ; git rebase local to move those commits back over to trunk before git svn dcommit. This helps a lot if you ever have to deal with a merge.

When I'm fixing particular bugs, I often create a branch names after the bug id.

Update: Removed the --tags and --branches arguments ... mostly because of how horribly Git SVN works with branches (don't try it!), and to make the init step nice and fast.

Git & Svn : Not Always A Match Made In Heaven

Apache is stuck using Subversion ... so I've been using the Git/Svn integration built into Git for a while now. The good news is that most of the Git workflow comes with it ... you can create private branches, do local commits to your local repository, and build up a series of changes to dcommit ("delta commit") into SVN.

But that doesn't always work. For reasons I don't understand (given that there have been no other commits to SVN since I started work in my private branch), I keep getting the following error:

Applying: Provide the missing asset request handler for the virtual "stack" folder.
Committing to https://svn.apache.org/repos/asf/tapestry/tapestry5/trunk ...
 M tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImpl.java
 M tapestry-core/src/main/java/org/apache/tapestry5/services/LibraryMapping.java
 M tapestry-core/src/test/java/org/apache/tapestry5/internal/services/ClasspathAssetAliasManagerImplTest.java
 A tapestry-core/src/test/java/org/apache/tapestry5/services/LibraryMappingTest.java
Committed r935569
W: 86533530aac8673a9e107e323de5201b7187270f and refs/remotes/origin/trunk differ, using rebase:
:040000 040000 9c78596ee3f916f012c51d8927b4aa31d497f17b 8eb2b9b4f28e825e223c736eaa664bb53018258e M tapestry-core
Current branch trunk is up to date.
# of revisions changed  
before:
 07b37e03cbc17012247d2221e795023c564d8228
0830b5f383dc94ae16088185efefac2e1358cf30
0bf378bcafc3f5372b67edc50d7de5bed8713cd0
95c87c5d7a2435df6bfced0d858bfdcb6ff26f22
3cd4ea4d9b225fd5013e1ce72cb9bac6d5b3e5e2
7b95d935099ebbbeb81845c1b8170a89d6ca6421
af310cfa9a5552aab2574c1e345b3beb049fb040
20805630fc67b83b4ca946b942716aeba4c80bef
b3ef5e069942a30e2dce45a35e4be16382c0108d
1be75a15b7f203c927bc2aa34f43dda59ca968e3
555d94ebab122a688b7a1c0af253bf73609f88f5
729757eb3c35e14e126cb6ef16f5032d95d1cc4a
79dcfa32b291454bf9c652d635374d60638b8fb8
304d12f9d7d040f4dc231d213df663fcdf3863b6
0d626a7b0648735ab83bc7a2fd241390eb92e4e2 

after:
 86533530aac8673a9e107e323de5201b7187270f
07b37e03cbc17012247d2221e795023c564d8228
0830b5f383dc94ae16088185efefac2e1358cf30
0bf378bcafc3f5372b67edc50d7de5bed8713cd0
95c87c5d7a2435df6bfced0d858bfdcb6ff26f22
3cd4ea4d9b225fd5013e1ce72cb9bac6d5b3e5e2
7b95d935099ebbbeb81845c1b8170a89d6ca6421
af310cfa9a5552aab2574c1e345b3beb049fb040
20805630fc67b83b4ca946b942716aeba4c80bef
b3ef5e069942a30e2dce45a35e4be16382c0108d
1be75a15b7f203c927bc2aa34f43dda59ca968e3
555d94ebab122a688b7a1c0af253bf73609f88f5
729757eb3c35e14e126cb6ef16f5032d95d1cc4a
79dcfa32b291454bf9c652d635374d60638b8fb8
304d12f9d7d040f4dc231d213df663fcdf3863b6
0d626a7b0648735ab83bc7a2fd241390eb92e4e2 
 If you are attempting to commit  merges, try running:
  git rebase --interactive --preserve-merges  refs/remotes/origin/trunk 
Before dcommitting
~/work/t5-project
$

I did the right things; git co trunk followed by git svn rebase, then git rebase revised-assets-12apr2010. It claimed to replay my branch changes on top of the trunk branch, but regardless, the dcommit failed.

Doing some hunting around with Google, I found a partial explanation, that at least gives me a way forward. I'd still like to know how I got into this predicament.

At this point I just keep blindly entering the command: git reset --hard 705ccfb1e27d303a9db62de755b2fcfcca9a02f6 ; git svn rebase; git svn dcommit and get one Git commit further each time (that's the Git hash code for my final change in my original branch). Joy.

Saturday, March 28, 2009

Installing Subversion 1.5 binaries in Ubuntu 8.04

I'm a little left in the lurch currently, because I need Subversion 1.5 client binaries in my Ubuntu 8.04 virtual machine (the one I use for training). This is because Eclipse check projects out in such with 1.5 compatibility (IDEA is kind enough to ask which version to use). In any case, since setting up my Tapestry Workspace involves a bit of command-line SVN, I found myself needing to upgrade SVN to 1.5.

With a little hunting around and some guesswork, I found the solution.

You need to add a new Software Sources location; this is a tool, "Software Sources" inside the Applications > System menu. Click the tab labeled "Third Party Tools" and add a new source. You'll be prompted to enter an "apt-get line": deb http://archive.ubuntu.com/ubuntu/ intrepid main

From there, go into Synaptic Package Manager. Find package "subversion" and you'll see that there's a version of 1.5 now available, thanks to the new software source. You can right click and select "Upgrade", then apply the changes.

Saturday, September 15, 2007

Mac OS X bundles vs. Subversion

If you work on Mac OS X, you may have noticed how cool Macs deal with complex documents, things like Keynote presentations or applications themselves. They're stored as directories. The Finder hides this, making them look and act like individual files. This works nicely, often the contents of a bundle are simple text and XML files ... whereas the equivalent under Windows is either a very proprietary (and potentially fragile) binary format, or multiple files and folders that YOU have to treat as a unit.

Alas, this all breaks down when using Subversion. You can't just check in MyPresentation.key into SVN ... it will create those pesky .svn directories inside the bundle, and those will be destroyed every time you save your presentation.

My solution to this is to convert the bundles into an archive, and check in the archive. The bundle folders are marked as svn:ignore. I guess this reveals that I mostly use SVN as a safe, structured backup.

In any case, manually creating those archives can be a pain. So ... out comes my solution to many problems: Ruby.

The goal here is to find bundles that need to be archived; do it efficiently (only update the archive if necessary) and do it recursively, seeking out bundles in sub-directories.

#!/usr/bin/ruby

# Used to prepare a directory for commit to Subversion. This is necessary for certain file types on Mac OS X because what appear to be files in the Finder
# are actually directories (Mac uses the term "bundle" for this concept). It is useless to put the .svn folder inside such a directory, because it will
# tend to be deleted whenever the "file" is saved.  
#
# Instead, we want to compress the directory to a single archive file; the bundle will be marked as svn:ignore.
#
# We use tar with Bzip2 compression, which is resource intensive to create, but 
# compresses much better than GZip or PKZip.
#
# The trick is that we only want to create the acrhive version when necessary; when 
# the archive does not exist, or when any file
# in the bundle is newer than the archive.

require 'optparse'

# Set via command line options

$extensions = %w{pages key oo3 graffle}
$recursive = true
$dry_run = false

# Queue of folders to search (for bundles)

$queue = []

def matching_extension(name)
  dotx = name.rindex('.')
  
  return false unless dotx
  
  ext = name[dotx + 1 .. -1]
  
  return $extensions.include?(ext)
end


# Iterate over the directory, identify bundles that may need to be compressed and (if recursive) subdirectories
# to search.
#
# path: string path for a directory
def search_directory(dirpath)
  
  Dir.foreach(dirpath) do |name|
    
    # Skip hidden files and directories
    next if name[0..0] == "."
    
    path = File.join(dirpath, name)
        
    next unless File.directory?(path)
                  
    if matching_extension(name)
      update_archive path
      next
    end
    
    if $recursive
      $queue << path
    end
    
  end
  
end


def needs_update(bundle_path, archive_path)
  
  return true unless File.exists?(archive_path)
  
  archive_mtime = File.mtime(archive_path)
  
  # The archive exists ... can we find a file inside the bundle thats newer?
  # This won't catch deletions, but that's ok.  Bundles tend to get completly
  # overwritten when any tiny thing changes.
  
  dirqueue = [bundle_path]

  until dirqueue.empty?
    
    dirpath = dirqueue.pop
    
    Dir.foreach(dirpath) do |name|
      
      path = File.join(dirpath, name)
      
      if File.directory?(path)
        dirqueue << path unless [".", ".."].include?(name)
        next
      end
      
      # Is this file newer?
      
      if File.mtime(path) > archive_mtime
        return true
      end
      
    end
    
  end
  
  return false
end

def update_archive(path)
  archive = path + ".tar.bz2"
  
  return unless needs_update(path, archive)

  if $dry_run
    puts "Would create #{archive}"
    return
  end

  puts "Creating #{archive}"
    
  dir = File.dirname(path)
  bundle = File.basename(path)
    
  # Could probably fork and do it in a subshell
  system "tar --create --file=#{archive} --bzip2 --directory=#{dir} #{bundle}"

end

$opts = OptionParser.new do |opts|
  
  opts.banner = "Usage: prepsvn [options]"

  opts.on("-d", "--dir DIR", "Add directory to search (if no directory specify, current directory is searched)") do |value|
    $queue << value
  end

  opts.on("-e", "--extension EXTENSION", "Add another extension to match when searching for bundles to archive") do |value|
    $extensions << value
  end
  
  opts.on("-N", "--non-recursive", "Do not search non-bundle sub directories for files to archive") do
    $recursive = false
  end
  
  opts.on("-D", "--dry-run", "Identify what archives would be created") do
    $dry_run = true
  end
  
  opts.on("-h", "--help", "Help for this command") do
    puts opts
    exit
  end
end

def fail(message)
    puts "Error: #{message}"
    puts $opts
end

begin
    $opts.parse!
rescue OptionParser::InvalidOption
    fail $!
end

# If no --dir specified, use the current directory.

if $queue.empty?
  $queue << Dir.getwd
end

until $queue.empty? 
  search_directory $queue.pop
end

I do love Ruby syntax, it is so minimal, and lets me follow my personal mantra less is more.

I'm sure there's some edge cases that aren't handle well, such as spaces in path names and maybe issues related to permissions. But it works for me.

You do need to have tar installed, in order to build the archives. I can't remember if that's built in to Mac OS X (probably) or whether I obtained it using Fink.

In any case, you need to remember to execute prepsvn in your workspace, to spot file bundles that need archiving, before you check in. It would be awesome if Subversion supported some client-side check-in hooks to do this automatically.