command :clone do |c|
  c.workflow :hg
  c.desc "Clone a repository"
  c.opt :pull, "Whether to do a pull from the destination (the alternative is to stream)", :short => '-p'
  c.opt :stream, "stream raw data uncompressed from repository", :short => '-u'
  c.opt :rev, "revision to clone up to (implies pull=True)", :short => '-r'
  c.opt :"no-update", "Don't do an update after cloning, leaving the directory, if local, empty"
  
  c.help <<-HELP
amp clone [options]+ src dest
  
  Make a copy of an existing repository.
  
  Create a copy of an existing repository in a new directory.  The
  source and destination are URLs, as passed to the repository
  function.  Returns a pair of repository objects, the source and
  newly created destination.
  
  The location of the source is added to the new repository's
  .hg/hgrc file, as the default to be used for future pulls and
  pushes.
  
  If an exception is raised, the partly cloned/updated destination
  repository will be deleted.
  
  Where options are:
HELP
  
  c.on_run do |opts, args|
    require 'uri'
    
    src, rev, checkout = *c.parse_url(args.shift)               # get the source url, revisions we want, and the checkout
    # puts [src, rev, checkout].inspect
    source = Amp::Repositories.pick opts[:global_config], src # make it an actual repository
    dest   = (dest = args.shift) || File.basename(src)        # get the destination URL
    
    Amp::UI::status "destination directory: #{dest}"
    
    # at this point, source is an {Amp::Repository} and dest is a {String}
    begin
      src  = c.local_path src
      dest = c.local_path dest
      copy = false
      
      raise Amp::Repositories::RepoError.new("destination #{dest} already exists") if File.exist? dest
      
      if source.can_copy? and ['file', nil].include? URI.parse(dest).scheme
        copy = !opts[:pull] && rev.empty?
      end
      
      if ['file', nil].include? URI.parse(dest).scheme # then it's local
        
        if source.local? && copy # then we're copying
          FileUtils.copy_entry src, dest # copy everything, pray it's pristine
          dest_repo = Amp::Repositories::LocalRepository.new dest, false, opts[:global_config]
        else # we have to pull
          # make the directory, cd into it, pull, and maaaaaaybe update
          dest_repo = Amp::Repositories::LocalRepository.new dest, true, opts[:global_config]
          dest_repo.clone source, :revs   => (rev ? rev.map {|r| source.lookup r } : []),
                                  :stream => opts[:stream] # the actual cloning which pulls
        end
        
      else
        
        # we're cloning ourselves to a faraway land
        # which DOESN'T HAPPEN unless source is local
        # remote - remote cloning just isn't supported in mercurial
        if source.local?
          dest_repo = Amp::Repositories.pick opts[:global_config], dest
          source.push dest_repo, :revs => rev.map {|r| source.lookup r }
        else
          raise Amp::RepoError.new("Remote -> Remote cloning is not yet supported")
        end
        
      end
      
      # NOW we write the hgrc file if the dest is local
      if dest_repo.local?
        dest_repo.hg_opener.open('hgrc', 'w') do |f|
          f.puts '[paths]'
          f.puts "default = #{File.expand_path(src).gsub('%', '%%')}"
        end
        
        if opts[:update]
          Amp::UI::status "updating working directory"
          dest_repo.update if opts[:update] # and here we add the files if we want to
        end
      end
      
      [source, dest_repo]
    rescue
      FileUtils.remove_entry dest # kill the dir if we've had any problems
    end
  end
end