validate-maven-repository.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. # Licensed to Elasticsearch under one or more contributor
  2. # license agreements. See the NOTICE file distributed with
  3. # this work for additional information regarding copyright
  4. # ownership. Elasticsearch licenses this file to you under
  5. # the Apache License, Version 2.0 (the "License"); you may
  6. # not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing,
  12. # software distributed under the License is distributed on
  13. # an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  14. # either express or implied. See the License for the specific
  15. # language governing permissions and limitations under the License.
  16. # Helper python script to check if a sonatype staging repo contains
  17. # all the required files compared to a local repository
  18. #
  19. # The script does the following steps
  20. #
  21. # 1. Scans the local maven repo for all files in /org/elasticsearch
  22. # 2. Opens a HTTP connection to the staging repo
  23. # 3. Executes a HEAD request for each file found in step one
  24. # 4. Compares the content-length response header with the real file size
  25. # 5. Return an error if those two numbers differ
  26. #
  27. # A pre requirement to run this, is to find out via the oss.sonatype.org web UI, how that repo is named
  28. # - After logging in you go to 'Staging repositories' and search for the one you just created
  29. # - Click into the `Content` tab
  30. # - Open any artifact (not a directory)
  31. # - Copy the link of `Repository Path` on the right and reuse that part of the URL
  32. #
  33. # Alternatively you can just use the name of the repository and reuse the rest (ie. the repository
  34. # named for the example below would have been named orgelasticsearch-1012)
  35. #
  36. #
  37. # Example call
  38. # python dev-tools/validate-maven-repository.py /path/to/repo/org/elasticsearch/ \
  39. # https://oss.sonatype.org/service/local/repositories/orgelasticsearch-1012/content/org/elasticsearch
  40. import sys
  41. import os
  42. import httplib
  43. import urlparse
  44. import re
  45. # Draw a simple progress bar, a couple of hundred HEAD requests might take a while
  46. # Note, when drawing this, it uses the carriage return character, so you should not
  47. # write anything in between
  48. def drawProgressBar(percent, barLen = 40):
  49. sys.stdout.write("\r")
  50. progress = ""
  51. for i in range(barLen):
  52. if i < int(barLen * percent):
  53. progress += "="
  54. else:
  55. progress += " "
  56. sys.stdout.write("[ %s ] %.2f%%" % (progress, percent * 100))
  57. sys.stdout.flush()
  58. if __name__ == "__main__":
  59. if len(sys.argv) != 3:
  60. print 'Usage: %s <localRep> <stagingRepo> [user:pass]' % (sys.argv[0])
  61. print ''
  62. print 'Example: %s /tmp/my-maven-repo/org/elasticsearch https://oss.sonatype.org/service/local/repositories/orgelasticsearch-1012/content/org/elasticsearch' % (sys.argv[0])
  63. else:
  64. sys.argv[1] = re.sub('/$', '', sys.argv[1])
  65. sys.argv[2] = re.sub('/$', '', sys.argv[2])
  66. localMavenRepo = sys.argv[1]
  67. endpoint = sys.argv[2]
  68. filesToCheck = []
  69. foundSignedFiles = False
  70. for root, dirs, files in os.walk(localMavenRepo):
  71. for file in files:
  72. # no metadata files (they get renamed from maven-metadata-local.xml to maven-metadata.xml while deploying)
  73. # no .properties and .repositories files (they dont get uploaded)
  74. if not file.startswith('maven-metadata') and not file.endswith('.properties') and not file.endswith('.repositories'):
  75. filesToCheck.append(os.path.join(root, file))
  76. if file.endswith('.asc'):
  77. foundSignedFiles = True
  78. print "Need to check %i files" % len(filesToCheck)
  79. if not foundSignedFiles:
  80. print '### Warning: No signed .asc files found'
  81. # set up http
  82. parsed_uri = urlparse.urlparse(endpoint)
  83. domain = parsed_uri.netloc
  84. if parsed_uri.scheme == 'https':
  85. conn = httplib.HTTPSConnection(domain)
  86. else:
  87. conn = httplib.HTTPConnection(domain)
  88. #conn.set_debuglevel(5)
  89. drawProgressBar(0)
  90. errors = []
  91. for idx, file in enumerate(filesToCheck):
  92. request_uri = parsed_uri.path + file[len(localMavenRepo):]
  93. conn.request("HEAD", request_uri)
  94. res = conn.getresponse()
  95. res.read() # useless call for head, but prevents httplib.ResponseNotReady raise
  96. absolute_url = parsed_uri.scheme + '://' + parsed_uri.netloc + request_uri
  97. if res.status == 200:
  98. content_length = res.getheader('content-length')
  99. local_file_size = os.path.getsize(file)
  100. if int(content_length) != int(local_file_size):
  101. errors.append('LENGTH MISMATCH: %s differs in size. local %s <=> %s remote' % (absolute_url, content_length, local_file_size))
  102. elif res.status == 404:
  103. errors.append('MISSING: %s' % absolute_url)
  104. elif res.status == 301 or res.status == 302:
  105. errors.append('REDIRECT: %s to %s' % (absolute_url, res.getheader('location')))
  106. else:
  107. errors.append('ERROR: %s http response: %s %s' %(absolute_url, res.status, res.reason))
  108. # update progressbar at the end
  109. drawProgressBar((idx+1)/float(len(filesToCheck)))
  110. print
  111. if len(errors) != 0:
  112. print 'The following errors occured (%s out of %s files)' % (len(errors), len(filesToCheck))
  113. print
  114. for error in errors:
  115. print error
  116. sys.exit(-1)