\subsection{darcs put}
\begin{code}
module Darcs.Commands.Put ( put ) where
import System ( ExitCode( ExitSuccess ), exitWith )
import Control.Monad ( when )
import Data.Maybe ( catMaybes )
import System.Directory ( createDirectory )
import Darcs.Commands ( DarcsCommand(..), nodefaults )
import Darcs.Arguments ( DarcsFlag( Quiet, Verbose
                                 ),
                        applyas, match_one_context, fix_filepath,
                        any_verbosity, ssh_cm, flagToString,
                      )
import Darcs.Repository ( withRepoLock, patchSetToPatches, read_repo, amInRepository, absolute_dir )
import Darcs.Patch.Bundle ( make_bundle )
import Darcs.Match ( have_patchset_match, get_one_patchset )
import Darcs.Repository.Prefs ( get_preflist, set_defaultrepo )
import Darcs.URL ( is_url, is_file, is_relative )
import Darcs.Utils ( withCurrentDirectory )
import Printer ( text, putDocLn, errorDoc )
import Darcs.SlurpDirectory ( empty_slurpy )
import Darcs.External ( execSSH )
import Darcs.RemoteApply ( remote_apply )
import Darcs.Commands.Init ( initialize )
import Darcs.Email ( make_email )
#include "impossible.h"
\end{code}
\begin{code}
put_description :: String 
put_description =
 "Makes a copy of the repository"
\end{code}
\options{put}
\haskell{put_help}
\begin{code}
put_help :: String
put_help = 
 "Put is the opposite of get. Put copies the content of the current \n" ++
 "repository and puts it in a newly created repository.\n"
\end{code}
\begin{code}
put ::DarcsCommand
put = DarcsCommand {command_name = "put",
                    command_help = put_help,
                    command_description = put_description,
                    command_extra_args = 1,
                    command_extra_arg_help = ["<NEW REPOSITORY>"],
                    command_command = put_cmd,
                    command_prereq = amInRepository,
                    command_get_arg_possibilities = get_preflist "repos",
                    command_argdefaults = nodefaults,
                    command_darcsoptions = [any_verbosity,
                                            match_one_context,
                                            applyas, ssh_cm]
                                           ++ command_darcsoptions initialize}
\end{code}
\begin{code}
put_cmd :: [DarcsFlag] -> [String] -> IO ()
put_cmd opts [unfixedrepodir] =
  let am_verbose = Verbose `elem` opts
      am_quiet = Quiet `elem` opts
      putVerbose s = when am_verbose $ putDocLn s
      putInfo s = when (not am_quiet) $ putDocLn s
      homedir = "."
      repodir = if is_relative unfixedrepodir
                then fix_filepath "" opts unfixedrepodir
                else unfixedrepodir
  in
 do
 -- Test to make sure we aren't trying to push to the current repo
 cur_absolute_repo_dir <- absolute_dir homedir
 req_absolute_repo_dir <- absolute_dir repodir
 when (cur_absolute_repo_dir == req_absolute_repo_dir) $
       fail "Can't put to current repository!"
 when (is_url req_absolute_repo_dir) $ errorDoc (text "Can't put to a URL!")

 putVerbose $ text "Creating repository"
 if is_file req_absolute_repo_dir
     then do createDirectory req_absolute_repo_dir
             withCurrentDirectory req_absolute_repo_dir $ (command_command initialize) opts []
     else do -- is_ssh req_absolute_repo_dir
             remoteInit req_absolute_repo_dir opts

 withCurrentDirectory cur_absolute_repo_dir $
                      withRepoLock opts $ \repository -> do
  set_defaultrepo req_absolute_repo_dir opts
  patchset <- if have_patchset_match opts
              then get_one_patchset opts
              else read_repo repository
  let patches = patchSetToPatches patchset
  when (null patches) $ do
          putInfo $
            text "No patches were selected to put. Nothing to be done."
          exitWith ExitSuccess
  let bundle = (make_bundle opts empty_slurpy [] patches)
      message = if is_file req_absolute_repo_dir
                then bundle
                else make_email req_absolute_repo_dir Nothing bundle Nothing
  out <- remote_apply opts req_absolute_repo_dir message
  putInfo out
put_cmd _ _ = impossible

remoteInit :: FilePath -> [DarcsFlag] -> IO ()
remoteInit repo opts = do
    let args = catMaybes $ map (flagToString $ command_darcsoptions initialize) opts
        command = "mkdir -p '"++path++
                  "' && cd '"++path++
                  "' && darcs initialize "++unwords args
    exitCode <- execSSH addr command
    when (exitCode /= ExitSuccess) $ 
         fail "Couldn't initialize remote repository."
  where (addr,':':path) = break (==':') repo
\end{code}

\emph{WARNING:} Put is far less optimized than get, especially for local
repositories.  We recommend avoiding use of put except for small
repositories.

Put is used when you already have a repository and want to make a copy
of it.  A typical use-case is when you want to branch your project.

Put works by first initializing a repository. If the new repository is
not on the local file system then darcs will login to the remote host
and run \verb!darcs init! there. After the new repository is created
all selected patches will be pushed just as with the command
\verb!push!.

\begin{options}
--apply-as
\end{options}

If you give the \verb!--apply-as! flag, darcs will use sudo to apply the
changes as a different user.  This can be useful if you want to set up a
system where several users can modify the same repository, but you don't
want to allow them full write access.  This isn't secure against skilled
malicious attackers, but at least can protect your repository from clumsy,
inept or lazy users.

\begin{options}
--context, --tag, --to-patch, --to-match
\end{options}
If you want to put a specific version of a repository, you have a few
options.  You can either use the \verb!--tag!, \verb!--to-patch! or
\verb!--to-match! options, or you can use the \verb!--context=FILENAME!
option, which specifies a file containing a context generated with
\verb!darcs changes --context!.  This allows you (for example) to include in
your compiled program an option to output the precise version of the
repository from which it was generated, and then perhaps ask users to
include this information in bug reports.

Note that when specifying \verb!--to-patch! or \verb!--to-match!, you may
get a version of your code that has never before been seen, if the patches
have gotten themselves reordered.  If you ever want to be able to precisely
reproduce a given version, you need either to tag it or create a context
file.
