1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#!/usr/bin/python
# @file template_verifier.py
# @brief Message template compatibility verifier.
#
# Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
# $License$
"""template_verifier is a script which will compare the
current repository message template with the "master" message template, accessible
via http://secondlife.com/app/message_template/master_message_template.msg
If [FILE] is specified, it will be checked against the master template.
If [FILE] [FILE] is specified, two local files will be checked against
each other.
"""
from os.path import realpath, dirname, join, exists
setup_path = join(dirname(realpath(__file__)), "setup-path.py")
if exists(setup_path):
execfile(setup_path)
import optparse
import os
import sys
import urllib
from indra import compatibility
from indra import llmessage
def die(msg):
print >>sys.stderr, msg
sys.exit(1)
MESSAGE_TEMPLATE = 'message_template.msg'
PRODUCTION_ACCEPTABLE = (compatibility.Same, compatibility.Newer)
DEVELOPMENT_ACCEPTABLE = (
compatibility.Same, compatibility.Newer,
compatibility.Older, compatibility.Mixed)
def getstatusall(command):
""" Like commands.getstatusoutput, but returns stdout and
stderr separately(to get around "killed by signal 15" getting
included as part of the file). Also, works on Windows."""
(input, out, err) = os.popen3(command, 't')
input.close() # send no input to the command
output = out.read()
error = err.read()
out.close()
status = err.close() # the status comes from the *last* pipe you close
return status, output, error
def getstatusoutput(command):
status, output, error = getstatusall(command)
return status, output
def compare(base, current, mode):
"""Compare the current template against the base template using the given
'mode' strictness:
development: Allows Same, Newer, Older, and Mixed
production: Allows only Same or Newer
Print out information about whether the current template is compatible
with the base template.
Returns a tuple of (bool, Compatibility)
Return True if they are compatible in this mode, False if not.
"""
base = llmessage.parseTemplateString(base)
current = llmessage.parseTemplateString(current)
compat = current.compatibleWithBase(base)
if mode == 'production':
acceptable = PRODUCTION_ACCEPTABLE
else:
acceptable = DEVELOPMENT_ACCEPTABLE
if type(compat) in acceptable:
return True, compat
return False, compat
def local_template_filename():
"""Returns the message template's default location relative to template_verifier.py:
./messages/message_template.msg."""
d = os.path.dirname(os.path.realpath(__file__))
return os.path.join(d, 'messages', MESSAGE_TEMPLATE)
def run(sysargs):
parser = optparse.OptionParser(
usage="usage: %prog [FILE] [FILE]",
description=__doc__)
parser.add_option(
'-m', '--mode', type='string', dest='mode',
default='development',
help="""[development|production] The strictness mode to use
while checking the template; see the wiki page for details about
what is allowed and disallowed by each mode:
http://wiki.secondlife.com/wiki/Template_verifier.py
""")
parser.add_option(
'-u', '--master_url', type='string', dest='master_url',
default='http://secondlife.com/app/message_template/master_message_template.msg',
help="""The url of the master message template.""")
options, args = parser.parse_args(sysargs)
# both current and master supplied in positional params
if len(args) == 2:
master_filename, current_filename = args
print "base:", master_filename
print "current:", current_filename
master = file(master_filename).read()
current = file(current_filename).read()
# only current supplied in positional param
elif len(args) == 1:
master = None
current_filename = args[0]
print "base: <master template from repository>"
print "current:", current_filename
current = file(current_filename).read()
# nothing specified, use defaults for everything
elif len(args) == 0:
master = None
current = None
else:
die("Too many arguments")
# fetch the master from the url (default or supplied)
if master is None:
master = urllib.urlopen(options.master_url).read()
# fetch the template for this build
if current is None:
current_filename = local_template_filename()
print "base: <master template from repository>"
print "current:", current_filename
current = file(current_filename).read()
acceptable, compat = compare(
master, current, options.mode)
def explain(header, compat):
print header
# indent compatibility explanation
print '\n\t'.join(compat.explain().split('\n'))
if acceptable:
explain("--- PASS ---", compat)
else:
explain("*** FAIL ***", compat)
return 1
if __name__ == '__main__':
sys.exit(run(sys.argv[1:]))
|