Uploader for maven central releases

Change-Id: Ic6d646890f5b5c4e3d79d1367760aa2d1b22d84c
diff --git a/tools/build/bazel/upload-sonatype.py b/tools/build/bazel/upload-sonatype.py
new file mode 100755
index 0000000..ef76d03
--- /dev/null
+++ b/tools/build/bazel/upload-sonatype.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+"""
+ Copyright 2018-present Open Networking Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+"""
+
+from subprocess import call
+import tempfile
+import hashlib
+import requests, os
+import xml.etree.ElementTree, shutil
+
+SONATYPE_USER=os.environ.get("SONATYPE_USER")
+SONATYPE_PASSWORD=os.environ.get("SONATYPE_PASSWORD")
+SONATYPE_PROFILE=os.environ.get("SONATYPE_PROFILE")
+UPLOAD_BASE="https://oss.sonatype.org/service/local/staging/deployByRepositoryId"
+
+CREATE_REPO_REQUEST_TEMPLATE = '''\
+<promoteRequest>
+    <data>
+      <description>%(description)</description>
+    </data>
+</promoteRequest>
+'''
+
+CLOSE_REPO_REQUEST_TEMPLATE = '''\
+<promoteRequest>
+    <data>
+      <description>%(description)</description>
+      <stagedRepositoryId>%(repo_id)</stagedRepositoryId>
+    </data>
+</promoteRequest>
+'''
+
+def hashlib_compute(hash, input_file, output_file):
+    with open(input_file, 'rb') as f:
+        for block in iter(lambda: f.read(100000), b''):
+            hash.update(block)
+        md5_string = hash.hexdigest()
+        output = open(output_file, "w")
+        output.write(md5_string + "\n")
+        f.close()
+        output.close()
+
+
+def generate_metadata_files(input_file):
+    # create a temporary directory to hold the metadata files
+    global tempdir
+    base_metadata_filename = tempdir + "/" + os.path.basename(input_file)
+
+    files = []
+
+    # generate the signature file
+    signature_filename = base_metadata_filename + ".asc"
+    call(["gpg", "--armor", "--detach-sig", "--output", signature_filename,  input_file])
+    files.append(signature_filename)
+
+    # generate the md5 checksum file
+    md5_filename = base_metadata_filename + ".md5"
+    md5 = hashlib.md5()
+    hashlib_compute(md5, input_file, md5_filename)
+    files.append(md5_filename)
+
+    # generate the SHA checksum file
+    sha1_filename = base_metadata_filename + ".sha1"
+    sha1 = hashlib.sha1()
+    hashlib_compute(sha1, input_file, sha1_filename)
+    files.append(sha1_filename)
+
+    return files
+
+
+def create_staging_repo(description):
+    create_request = CREATE_REPO_REQUEST_TEMPLATE.replace("%(description)", description)
+    url = "https://oss.sonatype.org/service/local/staging/profiles/87c0ccf277f362/start"
+    headers = {'Content-Type': 'application/xml'}
+    r = requests.post(url, create_request, headers=headers, auth=(SONATYPE_USER, SONATYPE_PASSWORD))
+    root = xml.etree.ElementTree.fromstring(r.text)
+    repo_id = root.find("data").find("stagedRepositoryId").text
+    print repo_id
+    return repo_id
+
+
+def close_staging_repo(description, repo_id):
+    close_request = CLOSE_REPO_REQUEST_TEMPLATE.replace("%(description)", description).replace("%(repo_id)", repo_id)
+    url = "https://oss.sonatype.org/service/local/staging/profiles/87c0ccf277f362/finish"
+    headers = {'Content-Type': 'application/xml'}
+    r = requests.post(url, close_request, headers=headers, auth=(SONATYPE_USER, SONATYPE_PASSWORD))
+
+
+def stage_file(file, repo_id, dest):
+    url = UPLOAD_BASE + "/" + repo_id + "/" + os.path.dirname(dest) + "/" + os.path.basename(file)
+    headers = {'Content-Type': 'application/xml'}
+    print("Uploading " + file)
+    with open(file, 'rb') as f:
+        r = requests.post(url, files={file: f}, headers=headers, auth=(SONATYPE_USER, SONATYPE_PASSWORD))
+
+
+def stage_files(files, dest):
+    for file in files:
+        stage_file(file=file, repo_id=repo_id, dest=dest)
+
+
+def upload_file(src, dest):
+    files = generate_metadata_files(src)
+    files.append(src)
+    stage_files(files, dest)
+
+
+if __name__ == '__main__':
+    import sys
+
+    if len(sys.argv) < 2:
+        print 'USAGE'
+        sys.exit(1)
+
+    if SONATYPE_USER == None:
+        print "Environment variable SONATYPE_USER must be set"
+        sys.exit(1)
+
+    if SONATYPE_PASSWORD == None:
+        print "Environment variable SONATYPE_PASSWORD must be set"
+        sys.exit(1)
+
+    if SONATYPE_PROFILE == None:
+        print "Environment variable SONATYPE_PROFILE must be set"
+        sys.exit(1)
+
+    input_list_file = sys.argv[1]
+    list_file = open(input_list_file, "r")
+    lines = list_file.readlines()
+    list_file.close()
+
+    tempdir = tempfile.mkdtemp(prefix="upload-sonatype-")
+    description = "test repo"
+    repo_id = create_staging_repo(description)
+    for line in lines:
+        s = line.split()
+        src = s[0]
+        dest = s[1]
+        upload_file(src, dest)
+    close_staging_repo(repo_id=repo_id, description=description)
+    shutil.rmtree(tempdir)