From 7531e218c179d00554c0ed332f1f100bc68290e8 Mon Sep 17 00:00:00 2001
From: Hannu Valtonen <hannu.valtonen@ohmu.fi>
Date: Tue, 12 Jan 2016 23:10:36 +0200
Subject: [PATCH] build.py: Make build script work on both Python2.x and
 Python3.x

While at it also add a missing dependency on lsof required by the
netstat plugin.

closes #512
---
 CHANGELOG.md |   1 +
 build.py     | 240 ++++++++++++++++++++++++++-------------------------
 2 files changed, 123 insertions(+), 118 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b398d00..56058b4d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ### Features
 - [#509](https://github.com/influxdb/telegraf/pull/509): Flatten JSON arrays with indices. Thanks @psilva261!
+- [#512](https://github.com/influxdata/telegraf/pull/512): Python 3 build script, add lsof dep to package. Thanks @Ormod!
 
 ### Bugfixes
 - [#506](https://github.com/influxdb/telegraf/pull/506): Ping input doesn't return response time metric when timeout. Thanks @titilambert!
diff --git a/build.py b/build.py
index cd8b74d0..a5892f26 100755
--- a/build.py
+++ b/build.py
@@ -92,31 +92,32 @@ def run(command, allow_failure=False, shell=False):
             out = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=shell)
         else:
             out = subprocess.check_output(command.split(), stderr=subprocess.STDOUT)
+        out = out.decode("utf8")
     except subprocess.CalledProcessError as e:
-        print ""
-        print ""
-        print "Executed command failed!"
-        print "-- Command run was: {}".format(command)
-        print "-- Failure was: {}".format(e.output)
+        print("")
+        print("")
+        print("Executed command failed!")
+        print("-- Command run was: {}".format(command))
+        print("-- Failure was: {}".format(e.output))
         if allow_failure:
-            print "Continuing..."
+            print("Continuing...")
             return None
         else:
-            print ""
-            print "Stopping."
+            print("")
+            print("Stopping.")
             sys.exit(1)
     except OSError as e:
-        print ""
-        print ""
-        print "Invalid command!"
-        print "-- Command run was: {}".format(command)
-        print "-- Failure was: {}".format(e)
+        print("")
+        print("")
+        print("Invalid command!")
+        print("-- Command run was: {}".format(command))
+        print("-- Failure was: {}".format(e))
         if allow_failure:
-            print "Continuing..."
+            print("Continuing...")
             return out
         else:
-            print ""
-            print "Stopping."
+            print("")
+            print("Stopping.")
             sys.exit(1)
     else:
         return out
@@ -173,42 +174,42 @@ def check_path_for(b):
             return full_path
 
 def check_environ(build_dir = None):
-    print "\nChecking environment:"
+    print("\nChecking environment:")
     for v in [ "GOPATH", "GOBIN", "GOROOT" ]:
-        print "\t- {} -> {}".format(v, os.environ.get(v))
+        print("\t- {} -> {}".format(v, os.environ.get(v)))
 
     cwd = os.getcwd()
     if build_dir == None and os.environ.get("GOPATH") and os.environ.get("GOPATH") not in cwd:
-        print "\n!! WARNING: Your current directory is not under your GOPATH. This may lead to build failures."
+        print("\n!! WARNING: Your current directory is not under your GOPATH. This may lead to build failures.")
 
 def check_prereqs():
-    print "\nChecking for dependencies:"
+    print("\nChecking for dependencies:")
     for req in prereqs:
-        print "\t- {} ->".format(req),
+        print("\t- {} ->".format(req),)
         path = check_path_for(req)
         if path:
-            print "{}".format(path)
+            print("{}".format(path))
         else:
-            print "?"
+            print("?")
     for req in optional_prereqs:
-        print "\t- {} (optional) ->".format(req),
+        print("\t- {} (optional) ->".format(req))
         path = check_path_for(req)
         if path:
-            print "{}".format(path)
+            print("{}".format(path))
         else:
-            print "?"
-    print ""
+            print("?")
+    print("")
 
 def upload_packages(packages, nightly=False):
-    print "Uploading packages to S3..."
-    print ""
+    print("Uploading packages to S3...")
+    print("")
     c = boto.connect_s3()
     # TODO(rossmcdonald) - Set to different S3 bucket for release vs nightly
     bucket = c.get_bucket('get.influxdb.org')
     for p in packages:
         name = os.path.join('telegraf', os.path.basename(p))
         if bucket.get_key(name) is None or nightly:
-            print "\t - Uploading {}...".format(name),
+            print("\t - Uploading {}...".format(name))
             k = Key(bucket)
             k.key = name
             if nightly:
@@ -216,41 +217,41 @@ def upload_packages(packages, nightly=False):
             else:
                 n = k.set_contents_from_filename(p, replace=False)
             k.make_public()
-            print "[ DONE ]"
+            print("[ DONE ]")
         else:
-            print "\t - Not uploading {}, already exists.".format(p)
-    print ""
+            print("\t - Not uploading {}, already exists.".format(p))
+    print("")
 
 def run_tests(race, parallel, timeout, no_vet):
     get_command = "go get -d -t ./..."
-    print "Retrieving Go dependencies...",
+    print("Retrieving Go dependencies...")
     sys.stdout.flush()
     run(get_command)
-    print "done."
-    print "Running tests:"
-    print "\tRace: ", race
+    print("done.")
+    print("Running tests:")
+    print("\tRace: ", race)
     if parallel is not None:
-        print "\tParallel:", parallel
+        print("\tParallel:", parallel)
     if timeout is not None:
-        print "\tTimeout:", timeout
+        print("\tTimeout:", timeout)
     sys.stdout.flush()
     p = subprocess.Popen(["go", "fmt", "./..."], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     out, err = p.communicate()
     if len(out) > 0 or len(err) > 0:
-        print "Code not formatted. Please use 'go fmt ./...' to fix formatting errors."
-        print out
-        print err
+        print("Code not formatted. Please use 'go fmt ./...' to fix formatting errors.")
+        print(out)
+        print(err)
         return False
     if not no_vet:
         p = subprocess.Popen(["go", "tool", "vet", "-composites=false", "./"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
         out, err = p.communicate()
         if len(out) > 0 or len(err) > 0:
-            print "Go vet failed. Please run 'go vet ./...' and fix any errors."
-            print out
-            print err
+            print("Go vet failed. Please run 'go vet ./...' and fix any errors.")
+            print(out)
+            print(err)
             return False
     else:
-        print "Skipping go vet ..."
+        print("Skipping go vet ...")
         sys.stdout.flush()
     test_command = "go test -v"
     if race:
@@ -262,10 +263,10 @@ def run_tests(race, parallel, timeout, no_vet):
     test_command += " ./..."
     code = os.system(test_command)
     if code != 0:
-        print "Tests Failed"
+        print("Tests Failed")
         return False
     else:
-        print "Tests Passed"
+        print("Tests Passed")
         return True
 
 def build(version=None,
@@ -279,26 +280,26 @@ def build(version=None,
           clean=False,
           outdir=".",
           goarm_version="6"):
-    print "-------------------------"
-    print ""
-    print "Build plan:"
-    print "\t- version: {}".format(version)
+    print("-------------------------")
+    print("")
+    print("Build plan:")
+    print("\t- version: {}".format(version))
     if rc:
-        print "\t- release candidate: {}".format(rc)
-    print "\t- commit: {}".format(commit)
-    print "\t- branch: {}".format(branch)
-    print "\t- platform: {}".format(platform)
-    print "\t- arch: {}".format(arch)
+        print("\t- release candidate: {}".format(rc))
+    print("\t- commit: {}".format(commit))
+    print("\t- branch: {}".format(branch))
+    print("\t- platform: {}".format(platform))
+    print("\t- arch: {}".format(arch))
     if arch == 'arm' and goarm_version:
-        print "\t- ARM version: {}".format(goarm_version)
-    print "\t- nightly? {}".format(str(nightly).lower())
-    print "\t- race enabled? {}".format(str(race).lower())
-    print ""
+        print("\t- ARM version: {}".format(goarm_version))
+    print("\t- nightly? {}".format(str(nightly).lower()))
+    print("\t- race enabled? {}".format(str(race).lower()))
+    print("")
 
     if not os.path.exists(outdir):
         os.makedirs(outdir)
     elif clean and outdir != '/':
-        print "Cleaning build directory..."
+        print("Cleaning build directory...")
         shutil.rmtree(outdir)
         os.makedirs(outdir)
 
@@ -306,14 +307,14 @@ def build(version=None,
         # If a release candidate, update the version information accordingly
         version = "{}rc{}".format(version, rc)
 
-    print "Starting build..."
-    for b, c in targets.iteritems():
-        print "\t- Building '{}'...".format(os.path.join(outdir, b)),
+    print("Starting build...")
+    for b, c in targets.items():
+        print("\t- Building '{}'...".format(os.path.join(outdir, b)),)
         build_command = ""
         build_command += "GOOS={} GOARCH={} ".format(platform, arch)
         if arch == "arm" and goarm_version:
             if goarm_version not in ["5", "6", "7", "arm64"]:
-                print "!! Invalid ARM build version: {}".format(goarm_version)
+                print("!! Invalid ARM build version: {}".format(goarm_version))
             build_command += "GOARM={} ".format(goarm_version)
         build_command += "go build -o {} ".format(os.path.join(outdir, b))
         if race:
@@ -331,20 +332,20 @@ def build(version=None,
             build_command += "-X main.Commit={}\" ".format(get_current_commit())
         build_command += c
         run(build_command, shell=True)
-        print "[ DONE ]"
-    print ""
+        print("[ DONE ]")
+    print("")
 
 def create_dir(path):
     try:
         os.makedirs(path)
     except OSError as e:
-        print e
+        print(e)
 
 def rename_file(fr, to):
     try:
         os.rename(fr, to)
     except OSError as e:
-        print e
+        print(e)
         # Return the original filename
         return fr
     else:
@@ -355,27 +356,27 @@ def copy_file(fr, to):
     try:
         shutil.copy(fr, to)
     except OSError as e:
-        print e
+        print(e)
 
 def create_package_fs(build_root):
-    print "\t- Creating a filesystem hierarchy from directory: {}".format(build_root)
+    print("\t- Creating a filesystem hierarchy from directory: {}".format(build_root))
     # Using [1:] for the path names due to them being absolute
     # (will overwrite previous paths, per 'os.path.join' documentation)
     dirs = [ INSTALL_ROOT_DIR[1:], LOG_DIR[1:], SCRIPT_DIR[1:], CONFIG_DIR[1:], LOGROTATE_DIR[1:] ]
     for d in dirs:
         create_dir(os.path.join(build_root, d))
-        os.chmod(os.path.join(build_root, d), 0755)
+        os.chmod(os.path.join(build_root, d), 0o755)
 
 def package_scripts(build_root):
-    print "\t- Copying scripts and sample configuration to build directory"
+    print("\t- Copying scripts and sample configuration to build directory")
     shutil.copyfile(INIT_SCRIPT, os.path.join(build_root, SCRIPT_DIR[1:], INIT_SCRIPT.split('/')[1]))
-    os.chmod(os.path.join(build_root, SCRIPT_DIR[1:], INIT_SCRIPT.split('/')[1]), 0644)
+    os.chmod(os.path.join(build_root, SCRIPT_DIR[1:], INIT_SCRIPT.split('/')[1]), 0o644)
     shutil.copyfile(SYSTEMD_SCRIPT, os.path.join(build_root, SCRIPT_DIR[1:], SYSTEMD_SCRIPT.split('/')[1]))
-    os.chmod(os.path.join(build_root, SCRIPT_DIR[1:], SYSTEMD_SCRIPT.split('/')[1]), 0644)
+    os.chmod(os.path.join(build_root, SCRIPT_DIR[1:], SYSTEMD_SCRIPT.split('/')[1]), 0o644)
     shutil.copyfile(LOGROTATE_SCRIPT, os.path.join(build_root, LOGROTATE_DIR[1:], "telegraf"))
-    os.chmod(os.path.join(build_root, LOGROTATE_DIR[1:], "telegraf"), 0644)
+    os.chmod(os.path.join(build_root, LOGROTATE_DIR[1:], "telegraf"), 0o644)
     shutil.copyfile(DEFAULT_CONFIG, os.path.join(build_root, CONFIG_DIR[1:], "telegraf.conf"))
-    os.chmod(os.path.join(build_root, CONFIG_DIR[1:], "telegraf.conf"), 0644)
+    os.chmod(os.path.join(build_root, CONFIG_DIR[1:], "telegraf.conf"), 0o644)
 
 def go_get(update=False):
     get_command = None
@@ -383,24 +384,27 @@ def go_get(update=False):
         get_command = "go get -u -f -d ./..."
     else:
         get_command = "go get -d ./..."
-    print "Retrieving Go dependencies...",
+    print("Retrieving Go dependencies...")
     run(get_command)
-    print "done.\n"
+    print("done.\n")
 
 def generate_md5_from_file(path):
     m = hashlib.md5()
     with open(path, 'rb') as f:
-        for chunk in iter(lambda: f.read(4096), b""):
-            m.update(chunk)
+        while True:
+            data = f.read(4096)
+            if not data:
+                break
+            m.update(data)
     return m.hexdigest()
 
 def build_packages(build_output, version, nightly=False, rc=None, iteration=1):
     outfiles = []
     tmp_build_dir = create_temp_dir()
     try:
-        print "-------------------------"
-        print ""
-        print "Packaging..."
+        print("-------------------------")
+        print("")
+        print("Packaging...")
         for p in build_output:
             # Create top-level folder displaying which platform (linux, etc)
             create_dir(os.path.join(tmp_build_dir, p))
@@ -419,11 +423,11 @@ def build_packages(build_output, version, nightly=False, rc=None, iteration=1):
                         b = b + '.exe'
                     fr = os.path.join(current_location, b)
                     to = os.path.join(build_root, INSTALL_ROOT_DIR[1:], b)
-                    print "\t- [{}][{}] - Moving from '{}' to '{}'".format(p, a, fr, to)
+                    print("\t- [{}][{}] - Moving from '{}' to '{}'".format(p, a, fr, to))
                     copy_file(fr, to)
                 # Package the directory structure
                 for package_type in supported_packages[p]:
-                    print "\t- Packaging directory '{}' as '{}'...".format(build_root, package_type),
+                    print("\t- Packaging directory '{}' as '{}'...".format(build_root, package_type))
                     name = "telegraf"
                     package_version = version
                     package_iteration = iteration
@@ -448,52 +452,53 @@ def build_packages(build_output, version, nightly=False, rc=None, iteration=1):
                         current_location)
                     if package_type == "rpm":
                         fpm_command += "--depends coreutils "
+                        fpm_command += "--depends lsof"
                     out = run(fpm_command, shell=True)
                     matches = re.search(':path=>"(.*)"', out)
                     outfile = None
                     if matches is not None:
                         outfile = matches.groups()[0]
                     if outfile is None:
-                        print "[ COULD NOT DETERMINE OUTPUT ]"
+                        print("[ COULD NOT DETERMINE OUTPUT ]")
                     else:
                         # Strip nightly version (the unix epoch) from filename
                         if nightly and package_type in ['deb', 'rpm']:
                             outfile = rename_file(outfile, outfile.replace("{}-{}".format(version, iteration), "nightly"))
                         outfiles.append(os.path.join(os.getcwd(), outfile))
-                        print "[ DONE ]"
+                        print("[ DONE ]")
                         # Display MD5 hash for generated package
-                        print "\t\tMD5 = {}".format(generate_md5_from_file(outfile))
-        print ""
+                        print("\t\tMD5 = {}".format(generate_md5_from_file(outfile)))
+        print("")
         return outfiles
     finally:
         # Cleanup
         shutil.rmtree(tmp_build_dir)
 
 def print_usage():
-    print "Usage: ./build.py [options]"
-    print ""
-    print "Options:"
-    print "\t --outdir=<path> \n\t\t- Send build output to a specified path. Defaults to ./build."
-    print "\t --arch=<arch> \n\t\t- Build for specified architecture. Acceptable values: x86_64|amd64, 386, arm, or all"
-    print "\t --goarm=<arm version> \n\t\t- Build for specified ARM version (when building for ARM). Default value is: 6"
-    print "\t --platform=<platform> \n\t\t- Build for specified platform. Acceptable values: linux, windows, darwin, or all"
-    print "\t --version=<version> \n\t\t- Version information to apply to build metadata. If not specified, will be pulled from repo tag."
-    print "\t --commit=<commit> \n\t\t- Use specific commit for build (currently a NOOP)."
-    print "\t --branch=<branch> \n\t\t- Build from a specific branch (currently a NOOP)."
-    print "\t --rc=<rc number> \n\t\t- Whether or not the build is a release candidate (affects version information)."
-    print "\t --iteration=<iteration number> \n\t\t- The iteration to display on the package output (defaults to 0 for RC's, and 1 otherwise)."
-    print "\t --race \n\t\t- Whether the produced build should have race detection enabled."
-    print "\t --package \n\t\t- Whether the produced builds should be packaged for the target platform(s)."
-    print "\t --nightly \n\t\t- Whether the produced build is a nightly (affects version information)."
-    print "\t --update \n\t\t- Whether dependencies should be updated prior to building."
-    print "\t --test \n\t\t- Run Go tests. Will not produce a build."
-    print "\t --parallel \n\t\t- Run Go tests in parallel up to the count specified."
-    print "\t --timeout \n\t\t- Timeout for Go tests. Defaults to 480s."
-    print "\t --clean \n\t\t- Clean the build output directory prior to creating build."
-    print ""
+    print("Usage: ./build.py [options]")
+    print("")
+    print("Options:")
+    print("\t --outdir=<path> \n\t\t- Send build output to a specified path. Defaults to ./build.")
+    print("\t --arch=<arch> \n\t\t- Build for specified architecture. Acceptable values: x86_64|amd64, 386, arm, or all")
+    print("\t --goarm=<arm version> \n\t\t- Build for specified ARM version (when building for ARM). Default value is: 6")
+    print("\t --platform=<platform> \n\t\t- Build for specified platform. Acceptable values: linux, windows, darwin, or all")
+    print("\t --version=<version> \n\t\t- Version information to apply to build metadata. If not specified, will be pulled from repo tag.")
+    print("\t --commit=<commit> \n\t\t- Use specific commit for build (currently a NOOP).")
+    print("\t --branch=<branch> \n\t\t- Build from a specific branch (currently a NOOP).")
+    print("\t --rc=<rc number> \n\t\t- Whether or not the build is a release candidate (affects version information).")
+    print("\t --iteration=<iteration number> \n\t\t- The iteration to display on the package output (defaults to 0 for RC's, and 1 otherwise).")
+    print("\t --race \n\t\t- Whether the produced build should have race detection enabled.")
+    print("\t --package \n\t\t- Whether the produced builds should be packaged for the target platform(s).")
+    print("\t --nightly \n\t\t- Whether the produced build is a nightly (affects version information).")
+    print("\t --update \n\t\t- Whether dependencies should be updated prior to building.")
+    print("\t --test \n\t\t- Run Go tests. Will not produce a build.")
+    print("\t --parallel \n\t\t- Run Go tests in parallel up to the count specified.")
+    print("\t --timeout \n\t\t- Timeout for Go tests. Defaults to 480s.")
+    print("\t --clean \n\t\t- Clean the build output directory prior to creating build.")
+    print("")
 
 def print_package_summary(packages):
-    print packages
+    print(packages)
 
 def main():
     # Command-line arguments
@@ -577,13 +582,13 @@ def main():
             print_usage()
             return 0
         else:
-            print "!! Unknown argument: {}".format(arg)
+            print("!! Unknown argument: {}".format(arg))
             print_usage()
             return 1
 
     if nightly:
         if rc:
-            print "!! Cannot be both nightly and a release candidate! Stopping."
+            print("!! Cannot be both nightly and a release candidate! Stopping.")
             return 1
         # In order to support nightly builds on the repository, we are adding the epoch timestamp
         # to the version so that version numbers are always greater than the previous nightly.
@@ -622,7 +627,7 @@ def main():
     platforms = []
     single_build = True
     if target_platform == 'all':
-        platforms = supported_builds.keys()
+        platforms = list(supported_builds.keys())
         single_build = False
     else:
         platforms = [target_platform]
@@ -655,7 +660,7 @@ def main():
     # Build packages
     if package:
         if not check_path_for("fpm"):
-            print "!! Cannot package without command 'fpm'. Stopping."
+            print("!! Cannot package without command 'fpm'. Stopping.")
             return 1
         packages = build_packages(build_output, version, nightly=nightly, rc=rc, iteration=iteration)
         # TODO(rossmcdonald): Add nice output for print_package_summary()
@@ -667,4 +672,3 @@ def main():
 
 if __name__ == '__main__':
     sys.exit(main())
-
-- 
GitLab