1#!/usr/bin/python
2
3"""
4Packages a new maven release.
5"""
6
7import os
8import re
9import shutil
10import subprocess
11import sys
12import xml.dom.minidom
13
14def mime_type_from_path(path):
15  if path.endswith(".pom"):
16    return "text/xml;charset=UTF-8"
17  elif path.endswith(".jar"):
18    return "application/java-archive"
19  return None
20
21if "__main__" == __name__:
22  # Compute directories relative to tools.
23  trunk_directory_path = os.path.realpath(os.path.join(
24    os.path.dirname(sys.argv[0]),
25    ".."))
26  maven_directory_path = os.path.realpath(os.path.join(
27    os.path.dirname(sys.argv[0]),
28    "..",
29    "..",
30    "maven",
31    "owasp-java-html-sanitizer",
32    "owasp-java-html-sanitizer"))
33  maven_metadata_path = os.path.join(
34    maven_directory_path,
35    "maven-metadata.xml")
36  version_template_directory_path = os.path.join(
37    maven_directory_path,
38    "+++version+++")
39  jar_path = os.path.join(
40    trunk_directory_path,
41    "distrib",
42    "lib",
43    "owasp-java-html-sanitizer.jar")
44  src_jar_path = os.path.join(
45    trunk_directory_path,
46    "distrib",
47    "lib",
48    "owasp-java-html-sanitizer-sources.jar")
49  doc_jar_path = os.path.join(
50    trunk_directory_path,
51    "distrib",
52    "lib",
53    "owasp-java-html-sanitizer-javadoc.jar")
54
55  # Make sure the directory_structures we expect exist.
56  assert os.path.isdir(maven_directory_path), maven_directory_path
57  assert os.path.isdir(trunk_directory_path), trunk_directory_path
58  assert os.path.isfile(maven_metadata_path), maven_metadata_path
59  assert os.path.isdir(version_template_directory_path), (
60         version_template_directory_path)
61  assert os.path.isfile(jar_path), jar_path
62  assert os.path.isfile(src_jar_path), src_jar_path
63  assert os.path.isfile(doc_jar_path), doc_jar_path
64
65  # Get svn info of the trunk directory.
66  svn_info_xml = (
67     subprocess.Popen(["svn", "info", "--xml", trunk_directory_path],
68                      stdout=subprocess.PIPE)
69    .communicate()[0])
70  svn_info = xml.dom.minidom.parseString(svn_info_xml)
71
72  # Process SVN output XML to find fields.
73  date_element = svn_info.getElementsByTagName("date")[0]
74  entry_element = svn_info.getElementsByTagName("entry")[0]
75  def inner_text(node):
76    if node.nodeType == 3: return node.nodeValue
77    if node.nodeType == 1:
78      return "".join([inner_text(child) for child in node.childNodes])
79    return ""
80
81  # Create a list of fields to use in substitution.
82  fields = {
83    "version": "r%s" % entry_element.getAttribute("revision"),
84    "timestamp": re.sub(r"[^.\d]|\.\d+", "", inner_text(date_element))
85  }
86
87  def replace_fields(s):
88    return re.sub(r"\+\+\+(\w+)\+\+\+", lambda m: fields[m.group(1)], s)
89
90  # List of files that need to have ##DUPE## and ##REPLACE## sections expanded
91  # NOTE(12 February 2013): We no longer rewrite maven_metadata_path since this
92  # project is now hosted in Maven Central, and maven_metadata used a
93  # groupId/artifactId pair that is incompatible with the convention used by
94  # Maven Central.
95  # All maven versions after 12 February are undiscoverable by looking at
96  # maven_metadata.
97  files_to_rewrite = []
98  new_file_paths = []
99
100  def copy_directory_structure_template(src_path, container_path):
101    dest_path = os.path.join(
102      container_path,
103      replace_fields(os.path.basename(src_path)))
104    if os.path.isdir(src_path):
105      os.mkdir(dest_path)
106      for child in os.listdir(src_path):
107        # Skip .svn directories.
108        if "." == child[0:1]: continue
109        copy_directory_structure_template(
110          os.path.join(src_path, child), dest_path)
111    else:
112      shutil.copyfile(src_path, dest_path)
113      mime_type = mime_type_from_path(dest_path)
114      if mime_type is None or mime_type.startswith("text/"):
115        files_to_rewrite.append(dest_path)
116      new_file_paths.append(dest_path)
117    return dest_path
118
119  def rewrite_file(path):
120    lines = []
121    in_file = open(path, "r")
122    try:
123      file_content = in_file.read()
124    finally:
125      in_file.close()
126    for line in file_content.split("\n"):
127      indentation = re.match(r"^\s*", line).group()
128      matches = re.findall(r"(<!--##REPLACE##(.*)##END##-->)", line)
129      if len(matches) >= 2: raise Error("%s: %s" % (path, line))
130      if len(matches):
131        match = matches[0]
132        line = "%s%s %s" % (indentation, replace_fields(match[1]), match[0])
133      else:
134        matches = re.findall("##DUPE##(.*)##END##", line)
135        if len(matches) >= 2: raise Error("%s: %s" % (path, line))
136        if len(matches):
137          match = matches[0]
138          lines.append("%s%s" % (indentation, replace_fields(match)))
139      lines.append(line)
140    out_file = open(path, "w")
141    try:
142      out_file.write("\n".join(lines))
143    finally:
144      out_file.close()
145
146  versioned_jar_path = os.path.join(
147    version_template_directory_path,
148    "owasp-java-html-sanitizer-+++version+++.jar")
149  versioned_src_jar_path = os.path.join(
150    version_template_directory_path,
151    "owasp-java-html-sanitizer-+++version+++-sources.jar")
152  versioned_doc_jar_path = os.path.join(
153    version_template_directory_path,
154    "owasp-java-html-sanitizer-+++version+++-javadoc.jar")
155
156  shutil.copyfile(jar_path, versioned_jar_path)
157  shutil.copyfile(src_jar_path, versioned_src_jar_path)
158  shutil.copyfile(doc_jar_path, versioned_doc_jar_path)
159  ok = False
160  version_directory_path = None
161  try:
162    version_directory_path = copy_directory_structure_template(
163      version_template_directory_path, maven_directory_path)
164    for file_to_rewrite in files_to_rewrite:
165      rewrite_file(file_to_rewrite)
166    ok = True
167  finally:
168    os.unlink(versioned_jar_path)
169    os.unlink(versioned_src_jar_path)
170    os.unlink(versioned_doc_jar_path)
171    if not ok and version_directory_path is not None:
172      shutil.rmtree(version_directory_path)
173
174  print "svn add '%s'" % version_directory_path
175
176  for new_file_path in new_file_paths:
177    mime_type = mime_type_from_path(new_file_path)
178    if mime_type is not None:
179      print "svn propset svn:mime-type '%s' '%s'" % (mime_type, new_file_path)
180