mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-25 02:01:34 +00:00

Most references to and dependencies on Subversion have been removed. "+svn" is now "+dev". Files that can't be fixed yet have a FIXME-GIT comment in them; most of these are in the website tests.
246 lines
8.4 KiB
Python
Executable File
246 lines
8.4 KiB
Python
Executable File
#!/usr/bin/env python
|
|
'''\
|
|
wmlmove -- generate commands to move a unit in the Wesnoth tree
|
|
|
|
usage: wmlmove --help
|
|
wmlmove [--revert] {src...} {dst}
|
|
wmlmove --delete src
|
|
|
|
This script facilitates moving or deleting units (referenced by their
|
|
.cfg file) along with all of their associated resources (images and
|
|
sounds). It may be run from the Wesnoth top-level directory or
|
|
anywhere beneath.
|
|
|
|
For purposes of this command, a "namespace identifier" is either the
|
|
basename of a campaign subdirectory or the special name "core",
|
|
indicating the units, images and sounds directories in data/core.
|
|
|
|
A source must be a namespace identifier, followed by "::", followed by
|
|
the name of a unit (the basename of its path without the .cfg
|
|
extension). A destination must be a namespace identifier, optionally
|
|
followed by :: and a unit class.
|
|
|
|
The script generates a sequence of shell commands. These commands
|
|
will move the unit and all its resources to appropriate places under
|
|
the target campaign or core directories. Appropriate VCS move commands
|
|
will be used on version-controlled files.
|
|
|
|
A resource is considered to belong to a unit (and moves with it) if the
|
|
resource is included in the unit .cfg and lives near the unit .cfg.
|
|
"Near" for a unit in the core data means anywhere in the core data,
|
|
but not in a campaign directory. "Near" for a unit under a
|
|
data/campaign directory means anywhere in that same campaign
|
|
directory, but not in core data or any other campaign directory.
|
|
|
|
The --revert option generates commands used to revert the result of a
|
|
specified move, undoing version-control operations as needed.
|
|
|
|
The --delete option removes a unit and its associated resources.
|
|
|
|
The --listspaces option lists all namespace identifiers.
|
|
|
|
The --imageclass option may be used to insert a directory path segment
|
|
into each destination filename just before the basename. Normally you
|
|
will not need to do this, as the image class will be deduced from the
|
|
second argument.
|
|
|
|
Note: After performing a move generated with this command, use
|
|
wmlscope to check that you have not left any references to the moved
|
|
units dangling.
|
|
|
|
Also be aware that this tool does nothing to update the unit
|
|
translation files.
|
|
|
|
Here is an example:
|
|
|
|
wmlmove Heir_To_The_Throne::Elvish_Lord Heir_To_The_Throne::Elvish_High_Lord Heir_To_The_Throne::Elvish_Lady core::elves
|
|
|
|
'''
|
|
|
|
import sys, os, time, re, getopt, sre_constants
|
|
from wesnoth.wmltools import *
|
|
|
|
if __name__ == "__main__":
|
|
# Process options.
|
|
(options, arguments) = getopt.getopt(sys.argv[1:], "dhi:lLr", ['delete', 'help', 'imageclass=', 'list', 'listspaces', 'revert'])
|
|
listem = False
|
|
listspaces = False
|
|
iclass = None
|
|
delete = False
|
|
revert = False
|
|
for (switch, val) in options:
|
|
if switch in ('-h', '--help'):
|
|
sys.stderr.write(__doc__)
|
|
sys.exit(0)
|
|
elif switch in ('-d', '--delete'):
|
|
delete = True
|
|
elif switch in ('-i', '--imageclass'):
|
|
iclass = val
|
|
elif switch in ('-l', '--list'):
|
|
listem = True
|
|
elif switch in ('-L', '--listspaces'):
|
|
listspaces = True
|
|
elif switch in ('-r', '--revert'):
|
|
listem = True
|
|
|
|
if not listspaces:
|
|
if len(arguments) == 0:
|
|
sys.stderr.write("wmlmove: at least one path to a unit is required.\n")
|
|
sys.stderr.write(__doc__)
|
|
sys.exit(1)
|
|
if not delete:
|
|
if len(arguments) == 1:
|
|
sys.stderr.write("wmlmove: a campaign name or 'core' is required.\n")
|
|
sys.stderr.write(__doc__)
|
|
sys.exit(1)
|
|
else:
|
|
dst = arguments.pop()
|
|
|
|
pop_to_top("wmlmove")
|
|
|
|
if listspaces:
|
|
print "\n".join(map(os.path.basename, scopelist()))
|
|
sys.exit(0)
|
|
|
|
# Locate the unit .cfgs to be moved.
|
|
srclist = []
|
|
for src in arguments:
|
|
try:
|
|
(namespace, resource) = src.split("::")
|
|
except ValueError:
|
|
sys.stderr.write(
|
|
"wmlmove: source name %s not in the form namespace::resource.\n" % src)
|
|
sys.exit(1)
|
|
if not is_namespace(namespace):
|
|
sys.stderr.write("wmlmove: no such scope as %s.\n" % namespace)
|
|
sys.exit(1)
|
|
src = resolve_unit_cfg(namespace, resource)
|
|
if not os.path.exists(src):
|
|
sys.stderr.write("wmlmove: can't find %s to move it.\n" % src)
|
|
sys.exit(1)
|
|
srclist.append(src)
|
|
|
|
# Validate the destination.
|
|
if not delete:
|
|
uclass = None
|
|
if "::" in dst:
|
|
(dst, uclass) = dst.split("::")
|
|
elif dst == "core":
|
|
sys.stderr.write("wmlmove: moves to core require a unit subclass.\n")
|
|
sys.exit(1)
|
|
dstdir = namespace_directory(dst)
|
|
if dstdir == None:
|
|
sys.stderr.write("wmlmove: invalid namespace %s\n" % dstdir)
|
|
sys.exit(1)
|
|
|
|
# Cross-reference all files.
|
|
cref = CrossRef(scopelist())
|
|
|
|
# Filter reference information on all files referenced in the source .cfgs
|
|
srcrefs = cref.subtract(srclist)
|
|
|
|
# List all relevant resources and their other references.
|
|
if listem:
|
|
for (name, defloc) in srcrefs.fileref.items():
|
|
print "Resource %s is used in %d files:" % \
|
|
(defloc, len(defloc.references))
|
|
defloc.dump_references()
|
|
|
|
# Generate the actual move commands
|
|
print "# Generated script from", " ".join(sys.argv[1:])
|
|
|
|
if not delete and not revert:
|
|
print '''
|
|
replace()
|
|
# Replace a specified string with another in any number of files
|
|
{
|
|
left="$1"; right="$2"; shift; shift;
|
|
|
|
for file in $*
|
|
do
|
|
if grep "$left" $file >/dev/null 2>&1
|
|
then
|
|
overwrite $file sed "s@$left@$right@g" $file
|
|
fi
|
|
done
|
|
}
|
|
|
|
overwrite()
|
|
# Replace a file with itself filtered by a command
|
|
{
|
|
opath=$PATH
|
|
PATH=/bin:/usr/bin
|
|
|
|
file=$1; shift
|
|
new=/tmp/over$$; old=/tmp/under$$
|
|
trap \'rm -f $new $old ; exit 1\' 1 2 15
|
|
|
|
if PATH=$opath "$@" >$new
|
|
then
|
|
cp $file $old # save the old file
|
|
trap "" 1 2 15 # We are committed; ignore signals
|
|
cp $new $file
|
|
else
|
|
echo "overwrite: $1 failed, $file unchanged" 1 >&2
|
|
exit 1
|
|
fi
|
|
rm -f $new $old
|
|
}
|
|
|
|
'''
|
|
print "chdir", os.getcwd()
|
|
if delete:
|
|
print "# Image deletions:"
|
|
for (name, defloc) in srcrefs.fileref.items():
|
|
for namespace in map(directory_namespace, srclist):
|
|
if namespace_member(name, namespace) and cref.refcount(name) == 0:
|
|
if revert:
|
|
print vcundelete(name)
|
|
else:
|
|
print vcdelete(name)
|
|
break
|
|
print ""
|
|
print "# .cfg deletions"
|
|
for filename in srclist:
|
|
if revert:
|
|
print vcundelete(filename)
|
|
else:
|
|
print vcdelete(filename)
|
|
else:
|
|
if iclass == None:
|
|
if not iclass:
|
|
if uclass:
|
|
iclass = uclass
|
|
else:
|
|
iclass = 'monsters'
|
|
print "# Defaulting image subclass to '%s', use -i to set it." % iclass
|
|
print "# Image moves:"
|
|
for (name, defloc) in srcrefs.fileref.items():
|
|
source = directory_namespace(name)
|
|
target = resolve_unit_image(dst, iclass, os.path.basename(name))
|
|
if revert:
|
|
if not namespace_member(name, source):
|
|
print vcunmove(name, target)
|
|
else:
|
|
if not namespace_member(name, dst):
|
|
print vcmove(name, target)
|
|
print ""
|
|
print "# .cfg moves and transformations"
|
|
for filename in srclist:
|
|
source = directory_namespace(filename)
|
|
target = resolve_unit_cfg(dst, uclass, os.path.basename(filename))
|
|
if revert:
|
|
if not namespace_member(filename, source):
|
|
print vcunmove(filename, target)
|
|
else:
|
|
if not namespace_member(filename, dst):
|
|
print vcmove(filename, target)
|
|
if iclass:
|
|
print "replace 'units/' 'units/%s/' %s" % (iclass, target)
|
|
if dst == "core":
|
|
print "replace '#textdomain wesnoth.*' '#textdomain wesnoth' %s" % target
|
|
else:
|
|
print "echo 'Warning: text domain will require manual change.'"
|
|
|
|
# wmlmove ends here
|