--- /dev/null
+stg-cp(1)
+=========
+Yann Dirson <ydirson@altern.org>
+v0.13, March 2007
+
+NAME
+----
+stg-cp - stgdesc:cp[]
+
+SYNOPSIS
+--------
+stg cp [OPTIONS] <file|dir> <newname>
+
+stg cp [OPTIONS] <files|dirs...> <dir>
+
+DESCRIPTION
+-----------
+
+Make git-controlled copies of git-controlled files. The copies are
+added to the Git index, so you can add them to a patch with
+stglink:refresh[].
+
+In the first form, copy a single file or a single directory, with a
+new name. The parent directory of <newname> must already exist;
+<newname> itself must not already exist, or the command will be
+interpreted as one of the second form.
+
+In the second form, copy one or several files and/or directories, into
+an existing directory.
+
+Directories are copied recursively. Only the git-controlled files
+under the named directories are copied and added to the index. Any
+file not known to Git will not be copied.
+
+CAVEATS
+-------
+
+The first form doesn't allow yet to overwrite an existing file
+(whether it could be recovered from Git or not), and the second form
+does not check before overwriting any file, possibly leading to loss
+of non-committed modifications.
+
+FUTURE OPTIONS
+--------------
+
+--all::
+ Also copy files not known to Git when copying a directory.
+
+--force::
+ Force overwriting of target files, even if overwritten files
+ have non-committed changes or are not known to Git.
+
+--dry-run::
+ Show which files would be added, and which would be modified
+ if --force would be added.
+
+StGIT
+-----
+Part of the StGIT suite - see gitlink:stg[7].
stgdesc:add[]
stglink:rm[]::
stgdesc:rm[]
+stglink:cp[]::
+ stgdesc:cp[]
stglink:status[]::
stgdesc:status[]
stglink:diff[]::
clean
clone
commit
+ cp
export
files
float
--- /dev/null
+
+__copyright__ = """
+Copyright (C) 2007, Yann Dirson <ydirson@altern.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+import sys, os
+from optparse import OptionParser, make_option
+
+from stgit.commands.common import *
+from stgit.utils import *
+from stgit import stack, git
+
+
+help = 'copy files inside the repository'
+usage = """%prog [options] [<file/dir> <newname> | <files/dirs...> <dir>]
+
+Copy of the files and dirs passed as arguments under another name or
+location inside the same repository."""
+
+options = []
+
+def func(parser, options, args):
+ """Copy files inside the repository
+ """
+ if len(args) < 1:
+ parser.error('incorrect number of arguments')
+
+ if not crt_series.get_current():
+ raise CmdException, 'No patches applied'
+
+ git.copy(args[0:-1], args[-1])
"""
import sys, os, popen2, re, gitmergeonefile
+from shutil import copyfile
from stgit import basedir
from stgit.utils import *
if __run('git-update-index --add --', files):
raise GitException, 'Unable to add file'
+def __copy_single(source, target, target2=''):
+ """Copy file or dir named 'source' to name target+target2"""
+
+ # "source" (file or dir) must match one or more git-controlled file
+ realfiles = _output_lines(['git-ls-files', source])
+ if len(realfiles) == 0:
+ raise GitException, '"%s" matches no git-controled files' % source
+
+ if os.path.isdir(source):
+ # physically copy the files, and record them to add them in one run
+ newfiles = []
+ re_string='^'+source+'/(.*)$'
+ prefix_regexp = re.compile(re_string)
+ for f in [f.strip() for f in realfiles]:
+ m = prefix_regexp.match(f)
+ if not m:
+ print '"%s" does not match "%s"' % (f, re_string)
+ assert(m)
+ newname = target+target2+'/'+m.group(1)
+ if not os.path.exists(os.path.dirname(newname)):
+ os.makedirs(os.path.dirname(newname))
+ copyfile(f, newname)
+ newfiles.append(newname)
+
+ add(newfiles)
+ else: # files, symlinks, ...
+ newname = target+target2
+ copyfile(source, newname)
+ add([newname])
+
+
+def copy(filespecs, target):
+ if os.path.isdir(target):
+ # target is a directory: copy each entry on the command line,
+ # with the same name, into the target
+ for filespec in filespecs:
+ filespec = filespec.rstrip('/')
+ basename = '/' + os.path.basename(filespec)
+ __copy_single(filespec, target, basename)
+
+ elif os.path.exists(target):
+ raise GitException, 'Target "%s" exists but is not a directory' % target
+ elif len(filespecs) != 1:
+ raise GitException, 'Cannot copy more than one file to non-directory'
+
+ else:
+ # at this point: len(filespecs)==1 and target does not exist
+
+ # check target directory
+ targetdir = os.path.dirname(target)
+ if targetdir != '' and not os.path.isdir(targetdir):
+ raise GitException, 'Target directory "%s" does not exist' % targetdir
+
+ __copy_single(filespecs[0].rstrip('/'), target)
+
+
def rm(files, force = False):
"""Remove a file from the repository
"""
'clean': 'clean',
'clone': 'clone',
'commit': 'commit',
+ 'cp': 'copy',
'export': 'export',
'files': 'files',
'float': 'float',
)
wccommands = (
'add',
+ 'cp',
'diff',
'resolved',
'rm',