\subsection{darcs put}
\begin{code}
module Put ( put ) where
import System ( ExitCode( ExitSuccess ), exitWith )
import Monad ( when )
import Directory ( createDirectory )
import IO ( isAlreadyExistsError )
import DarcsCommands ( DarcsCommand(..), nodefaults )
import DarcsArguments ( DarcsFlag( Quiet, Verbose
                                 ),
                        applyas, match_one_context, fix_filepath,
                        any_verbosity, pristine_tree, working_repo_dir,
                        disable_ssh_cm,
                      )
import Repository ( patchSetToPatches )
import DarcsRepo ( read_repo, am_in_repo,
                   absolute_dir, write_inventory )
import PatchBundle ( make_bundle )
import Match ( have_patchset_match, get_one_patchset )
import RepoPrefs ( write_default_prefs, get_preflist, set_defaultrepo )
import DarcsURL ( is_url, is_file, is_relative )
import DarcsUtils ( withCurrentDirectory, formatPath )
import Printer ( text, putDocLn, errorDoc )
import Pristine ( Pristine, createPristine, flagsToPristine,
                  pristineToFlagString )
import SlurpDirectory ( empty_slurpy )
import External ( execSSH )
import RemoteApply ( remote_apply )
#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 = am_in_repo,
                    command_get_arg_possibilities = get_preflist "repos",
                    command_argdefaults = nodefaults,
                    command_darcsoptions = [any_verbosity,working_repo_dir,
                                            match_one_context,
                                            applyas,pristine_tree,
                                            disable_ssh_cm]}
\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 `catch`
        (\e-> if isAlreadyExistsError e
              then return () -- I'm not sure this should be an error
                             -- so for the time being it isn't.
              else fail $ "Error when creating " ++ formatPath repodir ++ ".")
   withCurrentDirectory req_absolute_repo_dir $ do
     createDirectory "_darcs" `catch`
        (\e-> if isAlreadyExistsError e
              then fail "Target repository has already been initialized. Use 'push' instead."
              else fail $ "Error creating directory " ++ formatPath "_darcs" ++ ".")
     createPristine $ flagsToPristine opts
     createDirectory "_darcs/patches"
     createDirectory "_darcs/prefs"
     write_default_prefs
     write_inventory "." [[]]

  else do -- is_ssh req_absolute_repo_dir
     remoteInit req_absolute_repo_dir $ flagsToPristine opts

 withCurrentDirectory cur_absolute_repo_dir $ do
  set_defaultrepo req_absolute_repo_dir opts
  patchset <- if have_patchset_match opts
              then get_one_patchset opts
              else read_repo "."
  let patches = patchSetToPatches patchset
  when (null patches) $ do
          putInfo $
            text "No patches were selected to put. Nothing to be done."
          exitWith ExitSuccess

  out <- remote_apply opts req_absolute_repo_dir 
         (make_bundle opts empty_slurpy [] patches)
  putInfo out
put_cmd _ _ = impossible

remoteInit :: FilePath -> Pristine -> IO ()
remoteInit repo pristine = do
    let pristineArg = pristineToFlagString pristine
        command = "mkdir -p '"++path++
                  "' && cd '"++path++
                  "' && darcs init "++pristineArg
    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.
