You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by aw...@apache.org on 2015/07/07 00:51:48 UTC

[1/3] hadoop git commit: HADOOP-12127. some personalities are still using releaseaudit instead of asflicense (aw)

Repository: hadoop
Updated Branches:
  refs/heads/HADOOP-12111 0a607a24c -> dcde7e4a2


HADOOP-12127. some personalities are still using releaseaudit instead of asflicense (aw)


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/76ce1ce7
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/76ce1ce7
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/76ce1ce7

Branch: refs/heads/HADOOP-12111
Commit: 76ce1ce73b2df077a64db8f848443094460ae534
Parents: 0a607a2
Author: Allen Wittenauer <aw...@apache.org>
Authored: Mon Jul 6 15:47:32 2015 -0700
Committer: Allen Wittenauer <aw...@apache.org>
Committed: Mon Jul 6 15:47:32 2015 -0700

----------------------------------------------------------------------
 dev-support/personality/flink.sh       |  2 +-
 dev-support/personality/hadoop.sh      |  2 +-
 dev-support/personality/hbase.sh       |  2 +-
 dev-support/personality/tajo.sh        |  2 +-
 dev-support/personality/tez.sh         |  2 +-
 dev-support/test-patch.d/apache-rat.sh | 84 -----------------------------
 dev-support/test-patch.d/asflicense.sh | 84 +++++++++++++++++++++++++++++
 7 files changed, 89 insertions(+), 89 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/personality/flink.sh
----------------------------------------------------------------------
diff --git a/dev-support/personality/flink.sh b/dev-support/personality/flink.sh
index a32e2d6..de2a0f1 100755
--- a/dev-support/personality/flink.sh
+++ b/dev-support/personality/flink.sh
@@ -113,7 +113,7 @@ function personality_modules
       fi
       return
       ;;
-    releaseaudit)
+    asflicense)
       # this is very fast and provides the full path if we do it from
       # the root of the source
       personality_enqueue_module .

http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/personality/hadoop.sh
----------------------------------------------------------------------
diff --git a/dev-support/personality/hadoop.sh b/dev-support/personality/hadoop.sh
index 059d051..7722afb 100755
--- a/dev-support/personality/hadoop.sh
+++ b/dev-support/personality/hadoop.sh
@@ -183,7 +183,7 @@ function personality_modules
         return
       fi
       ;;
-    releaseaudit)
+    asflicense)
       # this is very fast and provides the full path if we do it from
       # the root of the source
       personality_enqueue_module .

http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/personality/hbase.sh
----------------------------------------------------------------------
diff --git a/dev-support/personality/hbase.sh b/dev-support/personality/hbase.sh
index 46ad390..d8ca901 100755
--- a/dev-support/personality/hbase.sh
+++ b/dev-support/personality/hbase.sh
@@ -50,7 +50,7 @@ function personality_modules
       fi
       return
       ;;
-    releaseaudit)
+    asflicense)
       # this is very fast and provides the full path if we do it from
       # the root of the source
       personality_enqueue_module . -DHBasePatchProcess

http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/personality/tajo.sh
----------------------------------------------------------------------
diff --git a/dev-support/personality/tajo.sh b/dev-support/personality/tajo.sh
index 719bada..56e5442 100755
--- a/dev-support/personality/tajo.sh
+++ b/dev-support/personality/tajo.sh
@@ -40,7 +40,7 @@ function personality_modules
       fi
       return
       ;;
-    releaseaudit)
+    asflicense)
       # this is very fast and provides the full path if we do it from
       # the root of the source
       personality_enqueue_module .

http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/personality/tez.sh
----------------------------------------------------------------------
diff --git a/dev-support/personality/tez.sh b/dev-support/personality/tez.sh
index 77ad624..1d6a227 100755
--- a/dev-support/personality/tez.sh
+++ b/dev-support/personality/tez.sh
@@ -40,7 +40,7 @@ function personality_modules
       fi
       return
       ;;
-    releaseaudit)
+    asflicense)
       # this is very fast and provides the full path if we do it from
       # the root of the source
       personality_enqueue_module .

http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/test-patch.d/apache-rat.sh
----------------------------------------------------------------------
diff --git a/dev-support/test-patch.d/apache-rat.sh b/dev-support/test-patch.d/apache-rat.sh
deleted file mode 100755
index 27349bf..0000000
--- a/dev-support/test-patch.d/apache-rat.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env bash
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You 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.
-
-if [[ ${BUILDTOOL} == maven
-  || ${BUILDTOOL} == ant ]]; then
-  add_plugin asflicense
-  add_test asflicense
-fi
-
-## @description  Verify all files have an Apache License
-## @audience     private
-## @stability    evolving
-## @replaceable  no
-## @return       0 on success
-## @return       1 on failure
-function asflicense_postapply
-{
-  local numpatch
-
-  big_console_header "Determining number of patched ASF License errors"
-
-  start_clock
-
-  personality_modules patch asflicense
-  case ${BUILDTOOL} in
-    maven)
-      modules_workers patch asflicense apache-rat:check
-    ;;
-    ant)
-      modules_workers patch asflicense releaseaudit
-    ;;
-    *)
-      return 0
-    ;;
-  esac
-
-  # RAT fails the build if there are license problems.
-  # so let's take advantage of that a bit.
-  if [[ $? == 0 ]]; then
-    add_vote_table 1 asflicense "Patch does not generate ASF License warnings."
-    return 0
-  fi
-
-  #shellcheck disable=SC2038
-  find "${BASEDIR}" -name rat.txt -o -name releaseaudit_report.txt \
-    | xargs cat > "${PATCH_DIR}/patch-asflicense.txt"
-
-  if [[ -s "${PATCH_DIR}/patch-asflicense.txt" ]] ; then
-    numpatch=$("${GREP}" -c '\!?????' "${PATCH_DIR}/patch-asflicense.txt")
-    echo ""
-    echo ""
-    echo "There appear to be ${numpatch} ASF License warnings after applying the patch."
-    if [[ -n ${numpatch}
-       && ${numpatch} -gt 0 ]] ; then
-      add_vote_table -1 asflicense "Patch generated ${numpatch} ASF License warnings."
-
-      echo "Lines that start with ????? in the ASF License "\
-          "report indicate files that do not have an Apache license header:" \
-            > "${PATCH_DIR}/patch-asflicense-problems.txt"
-
-      ${GREP} '\!?????' "${PATCH_DIR}/patch-asflicense.txt" \
-      >>  "${PATCH_DIR}/patch-asflicense-problems.txt"
-
-      add_footer_table asflicense "@@BASE@@/patch-asflicense-problems.txt"
-    fi
-  else
-    # if we're here, then maven actually failed
-    modules_messages patch asflicense true
-  fi
-  return 1
-}

http://git-wip-us.apache.org/repos/asf/hadoop/blob/76ce1ce7/dev-support/test-patch.d/asflicense.sh
----------------------------------------------------------------------
diff --git a/dev-support/test-patch.d/asflicense.sh b/dev-support/test-patch.d/asflicense.sh
new file mode 100755
index 0000000..27349bf
--- /dev/null
+++ b/dev-support/test-patch.d/asflicense.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+if [[ ${BUILDTOOL} == maven
+  || ${BUILDTOOL} == ant ]]; then
+  add_plugin asflicense
+  add_test asflicense
+fi
+
+## @description  Verify all files have an Apache License
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure
+function asflicense_postapply
+{
+  local numpatch
+
+  big_console_header "Determining number of patched ASF License errors"
+
+  start_clock
+
+  personality_modules patch asflicense
+  case ${BUILDTOOL} in
+    maven)
+      modules_workers patch asflicense apache-rat:check
+    ;;
+    ant)
+      modules_workers patch asflicense releaseaudit
+    ;;
+    *)
+      return 0
+    ;;
+  esac
+
+  # RAT fails the build if there are license problems.
+  # so let's take advantage of that a bit.
+  if [[ $? == 0 ]]; then
+    add_vote_table 1 asflicense "Patch does not generate ASF License warnings."
+    return 0
+  fi
+
+  #shellcheck disable=SC2038
+  find "${BASEDIR}" -name rat.txt -o -name releaseaudit_report.txt \
+    | xargs cat > "${PATCH_DIR}/patch-asflicense.txt"
+
+  if [[ -s "${PATCH_DIR}/patch-asflicense.txt" ]] ; then
+    numpatch=$("${GREP}" -c '\!?????' "${PATCH_DIR}/patch-asflicense.txt")
+    echo ""
+    echo ""
+    echo "There appear to be ${numpatch} ASF License warnings after applying the patch."
+    if [[ -n ${numpatch}
+       && ${numpatch} -gt 0 ]] ; then
+      add_vote_table -1 asflicense "Patch generated ${numpatch} ASF License warnings."
+
+      echo "Lines that start with ????? in the ASF License "\
+          "report indicate files that do not have an Apache license header:" \
+            > "${PATCH_DIR}/patch-asflicense-problems.txt"
+
+      ${GREP} '\!?????' "${PATCH_DIR}/patch-asflicense.txt" \
+      >>  "${PATCH_DIR}/patch-asflicense-problems.txt"
+
+      add_footer_table asflicense "@@BASE@@/patch-asflicense-problems.txt"
+    fi
+  else
+    # if we're here, then maven actually failed
+    modules_messages patch asflicense true
+  fi
+  return 1
+}


[3/3] hadoop git commit: HADOOP-12156. modernize smart-apply-patch (aw)

Posted by aw...@apache.org.
HADOOP-12156. modernize smart-apply-patch (aw)


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/dcde7e4a
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/dcde7e4a
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/dcde7e4a

Branch: refs/heads/HADOOP-12111
Commit: dcde7e4a23ca0a5dcd4b01104d2d39365b557bac
Parents: 3fee9f8
Author: Allen Wittenauer <aw...@apache.org>
Authored: Mon Jul 6 15:50:46 2015 -0700
Committer: Allen Wittenauer <aw...@apache.org>
Committed: Mon Jul 6 15:50:46 2015 -0700

----------------------------------------------------------------------
 dev-support/smart-apply-patch.sh | 628 ++++++++++++++++++++++++++--------
 dev-support/test-patch.sh        |   2 +-
 2 files changed, 492 insertions(+), 138 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/dcde7e4a/dev-support/smart-apply-patch.sh
----------------------------------------------------------------------
diff --git a/dev-support/smart-apply-patch.sh b/dev-support/smart-apply-patch.sh
index ddfd940..bfd2aeb 100755
--- a/dev-support/smart-apply-patch.sh
+++ b/dev-support/smart-apply-patch.sh
@@ -11,179 +11,533 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-#
-# Determine if the git diff patch file has prefixes.
-# These files are generated via "git diff" *without* the --no-prefix option.
-#
-# We can apply these patches more easily because we know that the a/ and b/
-# prefixes in the "diff" lines stands for the project root directory.
-# So we don't have to hunt for the project root.
-# And of course, we know that the patch file was generated using git, so we
-# know git apply can handle it properly.
-#
-# Arguments: git diff file name.
-# Return: 0 if it is a git diff with prefix; 1 otherwise.
-#
-has_prefix() {
-  awk '/^diff --git / { if ($3 !~ "^a/" || $4 !~ "^b/") { exit 1 } }
-    /^\+{3}|-{3} / { if ($2 !~ "^[ab]/" && $2 !~ "^/dev/null") { exit 1 } }' "$1"
-  return $?
-}
+# Make sure that bash version meets the pre-requisite
 
-PATCH_FILE=$1
-DRY_RUN=$2
-if [ -z "$PATCH_FILE" ]; then
-  echo usage: $0 patch-file
+if [[ -z "${BASH_VERSINFO}" ]] \
+   || [[ "${BASH_VERSINFO[0]}" -lt 3 ]] \
+   || [[ "${BASH_VERSINFO[0]}" -eq 3 && "${BASH_VERSINFO[1]}" -lt 2 ]]; then
+  echo "bash v3.2+ is required. Sorry."
   exit 1
 fi
 
-TMPDIR=${TMPDIR:-/tmp}
-PATCH=${PATCH:-patch} # allow overriding patch binary
+RESULT=0
+
+## @description  Print a message to stderr
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @param        string
+function yetus_error
+{
+  echo "$*" 1>&2
+}
 
-# Cleanup handler for temporary files
-TOCLEAN=""
-cleanup() {
-  if [[ -n ${TOCLEAN} ]]; then
-    rm $TOCLEAN
+## @description  Print a message to stderr if --debug is turned on
+## @audience     public
+## @stability    stable
+## @replaceable  no
+## @param        string
+function yetus_debug
+{
+  if [[ -n "${YETUS_SHELL_SCRIPT_DEBUG}" ]]; then
+    echo "[$(date) DEBUG]: $*" 1>&2
   fi
-  exit $1
 }
-trap "cleanup 1" HUP INT QUIT TERM
 
-# Allow passing "-" for stdin patches
-if [ "$PATCH_FILE" == "-" ]; then
-  PATCH_FILE="$TMPDIR/smart-apply.in.$RANDOM"
-  cat /dev/fd/0 > $PATCH_FILE
-  TOCLEAN="$TOCLEAN $PATCH_FILE"
-fi
+## @description  Clean the filesystem as appropriate and then exit
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @param        runresult
+function cleanup_and_exit
+{
+  local result=$1
 
-ISSUE_RE='^(HADOOP|YARN|MAPREDUCE|HDFS)-[0-9]+$'
-if [[ ${PATCH_FILE} =~ ^http || ${PATCH_FILE} =~ ${ISSUE_RE} ]]; then
-  # Allow downloading of patches
-  PFILE="$TMPDIR/smart-apply.in.$RANDOM"
-  TOCLEAN="$TOCLEAN $PFILE"
-  if [[ ${PATCH_FILE} =~ ^http ]]; then
-    patchURL="${PATCH_FILE}"
-  else # Get URL of patch from JIRA
-    wget -q -O "${PFILE}" "http://issues.apache.org/jira/browse/${PATCH_FILE}"
-    if [[ $? != 0 ]]; then
-      echo "Unable to determine what ${PATCH_FILE} may reference." 1>&2
-      cleanup 1
-    elif [[ $(grep -c 'Patch Available' "${PFILE}") == 0 ]]; then
-      echo "${PATCH_FILE} is not \"Patch Available\".  Exiting." 1>&2
-      cleanup 1
-    fi
-    relativePatchURL=$(grep -o '"/jira/secure/attachment/[0-9]*/[^"]*' "${PFILE}" | grep -v -e 'htm[l]*$' | sort | tail -1 | grep -o '/jira/secure/attachment/[0-9]*/[^"]*')
-    patchURL="http://issues.apache.org${relativePatchURL}"
+  if [[ ${PATCH_DIR} =~ ^/tmp/apply-patch
+    && -d ${PATCH_DIR} ]]; then
+    rm -rf "${PATCH_DIR}"
+  fi
+
+  # shellcheck disable=SC2086
+  exit ${result}
+}
+
+## @description  Setup the default global variables
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function setup_defaults
+{
+  PATCHURL=""
+  OSTYPE=$(uname -s)
+
+  # Solaris needs POSIX, not SVID
+  case ${OSTYPE} in
+    SunOS)
+      AWK=${AWK:-/usr/xpg4/bin/awk}
+      SED=${SED:-/usr/xpg4/bin/sed}
+      WGET=${WGET:-wget}
+      GIT=${GIT:-git}
+      GREP=${GREP:-/usr/xpg4/bin/grep}
+      PATCH=${PATCH:-/usr/gnu/bin/patch}
+      DIFF=${DIFF:-/usr/gnu/bin/diff}
+      FILE=${FILE:-file}
+    ;;
+    *)
+      AWK=${AWK:-awk}
+      SED=${SED:-sed}
+      WGET=${WGET:-wget}
+      GIT=${GIT:-git}
+      GREP=${GREP:-grep}
+      PATCH=${PATCH:-patch}
+      DIFF=${DIFF:-diff}
+      FILE=${FILE:-file}
+    ;;
+  esac
+
+  DRYRUNMODE=false
+  PATCH_DIR=/tmp
+  while [[ -e ${PATCH_DIR} ]]; do
+    PATCH_DIR=/tmp/apply-patch-${RANDOM}.${RANDOM}
+  done
+  PATCHMODES=("git" "patch")
+  PATCHMODE=""
+  PATCHPREFIX=0
+}
+
+## @description  Print the usage information
+## @audience     public
+## @stability    stable
+## @replaceable  no
+function yetus_usage
+{
+  echo "Usage: apply-patch.sh [options] patch-file | issue-number | http"
+  echo
+  echo "--debug                If set, then output some extra stuff to stderr"
+  echo "--dry-run              Check for patch viability without applying"
+  echo "--patch-dir=<dir>      The directory for working and output files (default '/tmp/apply-patch-(random))"
+  echo
+  echo "Shell binary overrides:"
+  echo "--file-cmd=<cmd>       The 'file' command to use (default 'file')"
+  echo "--grep-cmd=<cmd>       The 'grep' command to use (default 'grep')"
+  echo "--git-cmd=<cmd>        The 'git' command to use (default 'git')"
+  echo "--patch-cmd=<cmd>      The GNU-compatible 'patch' command to use (default 'patch')"
+  echo "--wget-cmd=<cmd>       The 'wget' command to use (default 'wget')"
+}
+
+## @description  Interpret the command line parameters
+## @audience     private
+## @stability    stable
+## @replaceable  no
+## @params       $@
+## @return       May exit on failure
+function parse_args
+{
+  local i
+
+  for i in "$@"; do
+    case ${i} in
+      --debug)
+        YETUS_SHELL_SCRIPT_DEBUG=true
+      ;;
+      --dry-run)
+        DRYRUNMODE=true
+      ;;
+      --file-cmd=*)
+        FILE=${i#*=}
+      ;;
+      --git-cmd=*)
+        GIT=${i#*=}
+      ;;
+      --grep-cmd=*)
+        GREP=${i#*=}
+      ;;
+      --help|-help|-h|help|--h|--\?|-\?|\?)
+        yetus_usage
+        exit 0
+      ;;
+      --patch-cmd=*)
+        PATCH=${i#*=}
+      ;;
+      --patch-dir=*)
+        PATCH_DIR=${i#*=}
+      ;;
+      --wget-cmd=*)
+        WGET=${i#*=}
+      ;;
+      --*)
+        ## PATCH_OR_ISSUE can't be a --.  So this is probably
+        ## a plugin thing.
+        continue
+      ;;
+      *)
+        PATCH_OR_ISSUE=${i#*=}
+      ;;
+    esac
+  done
+
+  if [[ ! -d ${PATCH_DIR} ]]; then
+    mkdir -p "${PATCH_DIR}"
+    if [[ $? != 0 ]] ; then
+      yetus_error "ERROR: Unable to create ${PATCH_DIR}"
+      cleanup_and_exit 1
+    fi
   fi
-  if [[ -n $DRY_RUN ]]; then
-    echo "Downloading ${patchURL}"
+}
+
+## @description Given a possible patch file, guess if it's a patch file without using smart-apply-patch
+## @audience private
+## @stability evolving
+## @param path to patch file to test
+## @return 0 we think it's a patch file
+## @return 1 we think it's not a patch file
+function guess_patch_file
+{
+  local patch=$1
+  local fileOutput
+
+  yetus_debug "Trying to guess is ${patch} is a patch file."
+  fileOutput=$("${FILE}" "${patch}")
+  if [[ $fileOutput =~ \ diff\  ]]; then
+    yetus_debug "file magic says it's a diff."
+    return 0
   fi
-  wget -q -O "${PFILE}" "${patchURL}"
-  if [[ $? != 0 ]]; then
-    echo "${PATCH_FILE} could not be downloaded." 1>&2
-    cleanup 1
+  fileOutput=$(head -n 1 "${patch}" | "${GREP}" -E "^(From [a-z0-9]* Mon Sep 17 00:00:00 2001)|(diff .*)|(Index: .*)$")
+  if [[ $? == 0 ]]; then
+    yetus_debug "first line looks like a patch file."
+    return 0
   fi
-  PATCH_FILE="${PFILE}"
-fi
+  return 1
+}
+
+## @description  Given ${PATCH_ISSUE}, determine what type of patch file is in use, and do the
+## @description  necessary work to place it into ${PATCH_DIR}/patch.
+## @audience     private
+## @stability    evolving
+## @replaceable  no
+## @return       0 on success
+## @return       1 on failure, may exit
+function locate_patch
+{
+  local notSureIfPatch=false
+  yetus_debug "locate patch"
 
-# Case for git-diff patches
-if grep -q "^diff --git" "${PATCH_FILE}"; then
-  GIT_FLAGS="--binary -v"
-  if has_prefix "$PATCH_FILE"; then
-    GIT_FLAGS="$GIT_FLAGS -p1"
+  # Allow passing "-" for stdin patches
+  if [[ ${PATCH_OR_ISSUE} == - ]]; then
+    PATCH_FILE="${PATCH_DIR}/patch"
+    cat /dev/fd/0 > "${PATCH_FILE}"
+  elif [[ -f ${PATCH_OR_ISSUE} ]]; then
+    PATCH_FILE="${PATCH_OR_ISSUE}"
   else
-    GIT_FLAGS="$GIT_FLAGS -p0"
+    if [[ ${PATCH_OR_ISSUE} =~ ^http ]]; then
+      echo "Patch is being downloaded at $(date) from"
+      PATCHURL="${PATCH_OR_ISSUE}"
+    else
+      ${WGET} -q -O "${PATCH_DIR}/jira" "http://issues.apache.org/jira/browse/${PATCH_OR_ISSUE}"
+
+      case $? in
+        0)
+        ;;
+        2)
+          yetus_error "ERROR: .wgetrc/.netrc parsing error."
+          cleanup_and_exit 1
+        ;;
+        3)
+          yetus_error "ERROR: File IO error."
+          cleanup_and_exit 1
+        ;;
+        4)
+          yetus_error "ERROR: URL ${PATCH_OR_ISSUE} is unreachable."
+          cleanup_and_exit 1
+        ;;
+        *)
+          yetus_error "ERROR: Unable to fetch ${PATCH_OR_ISSUE}."
+          cleanup_and_exit 1
+        ;;
+      esac
+
+      if [[ -z "${PATCH_FILE}" ]]; then
+        if [[ $(${GREP} -c 'Patch Available' "${PATCH_DIR}/jira") == 0 ]] ; then
+          if [[ ${JENKINS} == true ]]; then
+            yetus_error "ERROR: ${PATCH_OR_ISSUE} is not \"Patch Available\"."
+            cleanup_and_exit 1
+          else
+            yetus_error "WARNING: ${PATCH_OR_ISSUE} is not \"Patch Available\"."
+          fi
+        fi
+
+        relativePatchURL=$(${GREP} -o '"/jira/secure/attachment/[0-9]*/[^"]*' "${PATCH_DIR}/jira" | ${GREP} -v -e 'htm[l]*$' | sort | tail -1 | ${GREP} -o '/jira/secure/attachment/[0-9]*/[^"]*')
+        PATCHURL="http://issues.apache.org${relativePatchURL}"
+        if [[ ! ${PATCHURL} =~ \.patch$ ]]; then
+          notSureIfPatch=true
+        fi
+        echo "${ISSUE} patch is being downloaded at $(date) from"
+      fi
+    fi
+    if [[ -z "${PATCH_FILE}" ]]; then
+      ${WGET} -q -O "${PATCH_DIR}/patch" "${PATCHURL}"
+      if [[ $? != 0 ]];then
+        yetus_error "ERROR: ${PATCH_OR_ISSUE} could not be downloaded."
+        cleanup_and_exit 1
+      fi
+      PATCH_FILE="${PATCH_DIR}/patch"
+    fi
   fi
-  if [[ -z $DRY_RUN ]]; then
-    GIT_FLAGS="$GIT_FLAGS --stat --apply"
-    echo Going to apply git patch with: git apply "${GIT_FLAGS}"
-  else
-    GIT_FLAGS="$GIT_FLAGS --check"
+
+  if [[ ! -f "${PATCH_DIR}/patch" ]]; then
+    cp "${PATCH_FILE}" "${PATCH_DIR}/patch"
+    if [[ $? == 0 ]] ; then
+      echo "Patch file ${PATCH_FILE} copied to ${PATCH_DIR}"
+    else
+      yetus_error "ERROR: Could not copy ${PATCH_FILE} to ${PATCH_DIR}"
+      cleanup_and_exit 1
+    fi
   fi
-  # shellcheck disable=SC2086
-  git apply ${GIT_FLAGS} "${PATCH_FILE}"
-  if [[ $? == 0 ]]; then
-    cleanup 0
+
+  if [[ ! -f "${PATCH_DIR}/patch" ]]; then
+    cp "${PATCH_FILE}" "${PATCH_DIR}/patch"
+    if [[ $? == 0 ]] ; then
+      echo "Patch file ${PATCH_FILE} copied to ${PATCH_DIR}"
+    else
+      yetus_error "ERROR: Could not copy ${PATCH_FILE} to ${PATCH_DIR}"
+      cleanup_and_exit 1
+    fi
   fi
-  echo "git apply failed. Going to apply the patch with: ${PATCH}"
-fi
 
-# Come up with a list of changed files into $TMP
-TMP="$TMPDIR/smart-apply.paths.$RANDOM"
-TOCLEAN="$TOCLEAN $TMP"
+  if [[ ${notSureIfPatch} == "true" ]]; then
+    guess_patch_file "${PATCH_FILE}"
+    if [[ $? != 0 ]]; then
+      yetus_error "ERROR: ${PATCHURL} is not a patch file."
+      cleanup_and_exit 1
+    else
+      yetus_debug "The patch ${PATCHURL} was not named properly, but it looks like a patch file. proceeding, but issue/branch matching might go awry."
+    fi
+  fi
+}
+
+## @description  if patch-level zero, then verify we aren't
+## @description  just adding files
+## @audience     public
+## @stability    stable
+## @param        filename
+## @param        command
+## @param        [..]
+## @replaceable  no
+## @returns      $?
+function verify_zero
+{
+  local logfile=$1
+  shift
+  local dir
+
+  # don't return /dev/null
+  # shellcheck disable=SC2016
+  changed_files1=$(${AWK} 'function p(s){if(s!~"^/dev/null"){print s}}
+    /^diff --git /   { p($3); p($4) }
+    /^(\+\+\+|---) / { p($2) }' "${PATCH_DIR}/patch" | sort -u)
+
+  # maybe we interpreted the patch wrong? check the log file
+  # shellcheck disable=SC2016
+  changed_files2=$(${GREP} -E '^[cC]heck' "${logfile}" \
+    | ${AWK} '{print $3}' \
+    | ${SED} -e 's,\.\.\.$,,g')
 
-if $PATCH -p0 -E --dry-run < $PATCH_FILE 2>&1 > $TMP; then
-  PLEVEL=0
-  #if the patch applied at P0 there is the possability that all we are doing
-  # is adding new files and they would apply anywhere. So try to guess the
-  # correct place to put those files.
+  for filename in ${changed_files1} ${changed_files2}; do
 
-  TMP2="$TMPDIR/smart-apply.paths.2.$RANDOM"
-  TOCLEAN="$TOCLEAN $TMP2"
+    # leading prefix = bad
+    if [[ ${filename} =~ ^(a|b)/ ]]; then
+      return 1
+    fi
+
+    # touching an existing file is proof enough
+    # that pl=0 is good
+    if [[ -f ${filename} ]]; then
+      return 0
+    fi
 
-  egrep '^patching file |^checking file ' $TMP | awk '{print $3}' | grep -v /dev/null | sort -u > $TMP2
+    dir=$(dirname ${filename} 2>/dev/null)
+    if [[ -n ${dir} && -d ${dir} ]]; then
+      return 0
+    fi
+  done
 
-  if [ ! -s $TMP2 ]; then
-    echo "Error: Patch dryrun couldn't detect changes the patch would make. Exiting."
-    cleanup 1
+  # ¯\_(ツ)_/¯ - no way for us to know, all new files with no prefix!
+  yetus_error "WARNING: Patch only adds files; using patch level ${PATCHPREFIX}"
+  return 0
+}
+
+## @description  run the command, sending stdout and stderr to the given filename
+## @audience     public
+## @stability    stable
+## @param        filename
+## @param        command
+## @param        [..]
+## @replaceable  no
+## @returns      $?
+function run_and_redirect
+{
+  local logfile=$1
+  shift
+
+  # to the log
+  echo "${*}" > "${logfile}"
+  # the actual command
+  "${@}" >> "${logfile}" 2>&1
+}
+
+## @description git patch dryrun
+## @replaceable  no
+## @audience     private
+## @stability    evolving
+function git_dryrun
+{
+  local prefixsize=${1:-0}
+
+  while [[ ${prefixsize} -lt 4
+    && -z ${PATCHMODE} ]]; do
+    run_and_redirect "${PATCH_DIR}/apply-patch-git-dryrun.log" \
+       "${GIT}" apply --binary -v --check "-p${prefixsize}" "${PATCH_FILE}"
+    if [[ $? == 0 ]]; then
+      PATCHPREFIX=${prefixsize}
+      PATCHMODE=git
+      echo "Verifying the patch:"
+      cat "${PATCH_DIR}/apply-patch-git-dryrun.log"
+      break
+    fi
+    ((prefixsize=prefixsize+1))
+  done
+
+  if [[ ${prefixsize} -eq 0 ]]; then
+    verify_zero "${PATCH_DIR}/apply-patch-git-dryrun.log"
+    if [[ $? != 0 ]]; then
+      PATCHMODE=""
+      PATCHPREFIX=""
+      git_dryrun 1
+    fi
   fi
+}
 
-  #first off check that all of the files do not exist
-  FOUND_ANY=0
-  for CHECK_FILE in $(cat $TMP2)
-  do
-    if [[ -f $CHECK_FILE ]]; then
-      FOUND_ANY=1
+## @description  patch patch dryrun
+## @replaceable  no
+## @audience     private
+## @stability    evolving
+function patch_dryrun
+{
+  local prefixsize=${1:-0}
+
+  while [[ ${prefixsize} -lt 4
+    && -z ${PATCHMODE} ]]; do
+    run_and_redirect "${PATCH_DIR}/apply-patch-patch-dryrun.log" \
+      "${PATCH}" "-p${prefixsize}" -E --dry-run < "${PATCH_FILE}"
+    if [[ $? == 0 ]]; then
+      PATCHPREFIX=${prefixsize}
+      PATCHMODE=patch
+      if [[ ${DRYRUNMODE} == true ]]; then
+        echo "Verifying the patch:"
+        cat "${PATCH_DIR}/apply-patch-patch-dryrun.log"
+      fi
+      break
     fi
+    ((prefixsize=prefixsize+1))
   done
 
-  if [[ "$FOUND_ANY" = "0" ]]; then
-    #all of the files are new files so we have to guess where the correct place to put it is.
+  if [[ ${prefixsize} -eq 0 ]]; then
+    verify_zero "${PATCH_DIR}/apply-patch-patch-dryrun.log"
+    if [[ $? != 0 ]]; then
+      PATCHMODE=""
+      PATCHPREFIX=""
+      patch_dryrun 1
+    fi
+  fi
+}
+
+## @description  driver for dryrun methods
+## @replaceable  no
+## @audience     private
+## @stability    evolving
+function dryrun
+{
+  local method
 
-    # if all of the lines start with a/ or b/, then this is a git patch that
-    # was generated without --no-prefix
-    if ! grep -qv '^a/\|^b/' $TMP2 ; then
-      echo Looks like this is a git patch. Stripping a/ and b/ prefixes
-      echo and incrementing PLEVEL
-      PLEVEL=$[$PLEVEL + 1]
-      sed -i -e 's,^[ab]/,,' $TMP2
+  for method in "${PATCHMODES[@]}"; do
+    if declare -f ${method}_dryrun >/dev/null; then
+      "${method}_dryrun"
     fi
+    if [[ -n ${PATCHMODE} ]]; then
+      break
+    fi
+  done
 
-    PREFIX_DIRS_AND_FILES=$(cut -d '/' -f 1 $TMP2 | sort -u)
- 
-    # if we are at the project root then nothing more to do
-    if [[ -d hadoop-common-project ]]; then
-      echo Looks like this is being run at project root
+  if [[ -n ${PATCHMODE} ]]; then
+    RESULT=0
+    return 0
+  fi
+  RESULT=1
+  return 1
+}
 
-    # if all of the lines start with hadoop-common/, hadoop-hdfs/, hadoop-yarn/ or hadoop-mapreduce/, this is
-    # relative to the hadoop root instead of the subproject root, so we need
-    # to chop off another layer
-    elif [[ "$PREFIX_DIRS_AND_FILES" =~ ^(hadoop-common-project|hadoop-hdfs-project|hadoop-yarn-project|hadoop-mapreduce-project)$ ]]; then
+## @description  git patch apply
+## @replaceable  no
+## @audience     private
+## @stability    evolving
+function git_apply
+{
+  echo "Applying the patch:"
+  run_and_redirect "${PATCH_DIR}/apply-patch-git-apply.log" \
+    "${GIT}" apply --binary -v --stat --apply "-p${PATCHPREFIX}" "${PATCH_FILE}"
+  cat "${PATCH_DIR}/apply-patch-git-apply.log"
+}
 
-      echo Looks like this is relative to project root. Increasing PLEVEL
-      PLEVEL=$[$PLEVEL + 1]
 
-    elif ! echo "$PREFIX_DIRS_AND_FILES" | grep -vxq 'hadoop-common-project\|hadoop-hdfs-project\|hadoop-yarn-project\|hadoop-mapreduce-project' ; then
-      echo Looks like this is a cross-subproject patch. Try applying from the project root
-      cleanup 1
+## @description  patch patch apply
+## @replaceable  no
+## @audience     private
+## @stability    evolving
+function patch_apply
+{
+  echo "Applying the patch:"
+  run_and_redirect "${PATCH_DIR}/apply-patch-patch-apply.log" \
+    "${PATCH}" "-p${PATCHPREFIX}" -E < "${PATCH_FILE}"
+  cat "${PATCH_DIR}/apply-patch-patch-apply.log"
+}
+
+
+## @description  driver for patch apply methods
+## @replaceable  no
+## @audience     private
+## @stability    evolving
+function apply
+{
+  if declare -f ${PATCHMODE}_apply >/dev/null; then
+    "${PATCHMODE}_apply"
+    if [[ $? -gt 0 ]]; then
+      RESULT=1
+    else
+      RESULT=0
     fi
+  else
+    yetus_error "ERROR: Patching method ${PATCHMODE} does not have a way to apply patches!"
+    RESULT=1
   fi
-elif $PATCH -p1 -E --dry-run < $PATCH_FILE 2>&1 > /dev/null; then
-  PLEVEL=1
-elif $PATCH -p2 -E --dry-run < $PATCH_FILE 2>&1 > /dev/null; then
-  PLEVEL=2
-else
-  echo "The patch does not appear to apply with p0 to p2";
-  cleanup 1;
-fi
+}
+
+trap "cleanup_and_exit 1" HUP INT QUIT TERM
 
-# If this is a dry run then exit instead of applying the patch
-if [[ -n $DRY_RUN ]]; then
-  cleanup 0;
+setup_defaults
+
+parse_args "$@"
+
+locate_patch
+
+dryrun
+
+if [[ ${RESULT} -gt 0 ]]; then
+  yetus_error "ERROR: Aborting! The patch cannot be verified."
+  cleanup_and_exit ${RESULT}
 fi
 
-echo Going to apply patch with: $PATCH -p$PLEVEL
-$PATCH -p$PLEVEL -E < $PATCH_FILE
+if [[ ${DRYRUNMODE} == false ]]; then
+  apply
+fi
 
-cleanup $?
+cleanup_and_exit ${RESULT}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/hadoop/blob/dcde7e4a/dev-support/test-patch.sh
----------------------------------------------------------------------
diff --git a/dev-support/test-patch.sh b/dev-support/test-patch.sh
index f93cb4a..793c42f 100755
--- a/dev-support/test-patch.sh
+++ b/dev-support/test-patch.sh
@@ -1601,7 +1601,7 @@ function verify_patch_file
   # Before building, check to make sure that the patch is valid
   export PATCH
 
-  "${BINDIR}/smart-apply-patch.sh" "${PATCH_DIR}/patch" dryrun
+  "${BINDIR}/smart-apply-patch.sh" --dry-run "${PATCH_DIR}/patch"
   if [[ $? != 0 ]] ; then
     echo "PATCH APPLICATION FAILED"
     add_vote_table -1 patch "The patch command could not apply the patch during dryrun."


[2/3] hadoop git commit: HADOOP-12135. cleanup releasedocmaker

Posted by aw...@apache.org.
HADOOP-12135. cleanup releasedocmaker


Project: http://git-wip-us.apache.org/repos/asf/hadoop/repo
Commit: http://git-wip-us.apache.org/repos/asf/hadoop/commit/3fee9f8d
Tree: http://git-wip-us.apache.org/repos/asf/hadoop/tree/3fee9f8d
Diff: http://git-wip-us.apache.org/repos/asf/hadoop/diff/3fee9f8d

Branch: refs/heads/HADOOP-12111
Commit: 3fee9f8d18dd60d83da674b3cfbefe666915fad8
Parents: 76ce1ce
Author: Allen Wittenauer <aw...@apache.org>
Authored: Mon Jul 6 15:49:03 2015 -0700
Committer: Allen Wittenauer <aw...@apache.org>
Committed: Mon Jul 6 15:49:03 2015 -0700

----------------------------------------------------------------------
 dev-support/releasedocmaker.py | 384 +++++++++++++++++++-----------------
 1 file changed, 207 insertions(+), 177 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hadoop/blob/3fee9f8d/dev-support/releasedocmaker.py
----------------------------------------------------------------------
diff --git a/dev-support/releasedocmaker.py b/dev-support/releasedocmaker.py
index 8e68b3c..6e01260 100755
--- a/dev-support/releasedocmaker.py
+++ b/dev-support/releasedocmaker.py
@@ -19,6 +19,7 @@
 from glob import glob
 from optparse import OptionParser
 from time import gmtime, strftime
+import pprint
 import os
 import re
 import sys
@@ -99,23 +100,44 @@ def mstr(obj):
     return ""
   return unicode(obj)
 
-def buildindex(master):
+def buildindex(title,license):
   versions=reversed(sorted(glob("[0-9]*.[0-9]*.[0-9]*")))
   with open("index.md","w") as indexfile:
+    if license is True:
+      indexfile.write(asflicense)
     for v in versions:
-      indexfile.write("* Apache Hadoop v%s\n" % (v))
+      indexfile.write("* %s v%s\n" % (title,v))
       for k in ("Changes","Release Notes"):
-        indexfile.write("    *  %s\n" %(k))
-        indexfile.write("        * [Combined %s](%s/%s.%s.html)\n" \
+        indexfile.write("    * %s (%s/%s.%s.html)\n" \
           % (k,v,k.upper().replace(" ",""),v))
-        if not master:
-          indexfile.write("        * [Hadoop Common %s](%s/%s.HADOOP.%s.html)\n" \
-            % (k,v,k.upper().replace(" ",""),v))
-          for p in ("HDFS","MapReduce","YARN"):
-            indexfile.write("        * [%s %s](%s/%s.%s.%s.html)\n" \
-              % (p,k,v,k.upper().replace(" ",""),p.upper(),v))
   indexfile.close()
 
+class GetVersions:
+  """ yo """
+  def __init__(self,versions, projects):
+    versions = versions
+    projects = projects
+    self.newversions = []
+    pp = pprint.PrettyPrinter(indent=4)
+    at=0
+    end=1
+    count=100
+    versions.sort()
+    print "Looking for %s through %s"%(versions[0],versions[-1])
+    for p in projects:
+      resp = urllib.urlopen("https://issues.apache.org/jira/rest/api/2/project/%s/versions"%p)
+      data = json.loads(resp.read())
+      for d in data:
+        if d['name'][0].isdigit and versions[0] <= d['name'] and d['name'] <= versions[-1]:
+          print "Adding %s to the list" % d['name']
+          self.newversions.append(d['name'])
+    newlist=list(set(self.newversions))
+    self.newversions=newlist
+
+  def getlist(self):
+      pp = pprint.PrettyPrinter(indent=4)
+      return(self.newversions)
+
 class Version:
   """Represents a version number"""
   def __init__(self, data):
@@ -261,8 +283,10 @@ class Jira:
 class JiraIter:
   """An Iterator of JIRAs"""
 
-  def __init__(self, versions):
-    self.versions = versions
+  def __init__(self, version, projects):
+    self.version = version
+    self.projects = projects
+    v=str(version).replace("-SNAPSHOT","")
 
     resp = urllib.urlopen("https://issues.apache.org/jira/rest/api/2/field")
     data = json.loads(resp.read())
@@ -276,7 +300,7 @@ class JiraIter:
     end=1
     count=100
     while (at < end):
-      params = urllib.urlencode({'jql': "project in (HADOOP,HDFS,MAPREDUCE,YARN) and fixVersion in ('"+"' , '".join([str(v).replace("-SNAPSHOT","") for v in versions])+"') and resolution = Fixed", 'startAt':at, 'maxResults':count})
+      params = urllib.urlencode({'jql': "project in ('"+"' , '".join(projects)+"') and fixVersion in ('"+v+"') and resolution = Fixed", 'startAt':at, 'maxResults':count})
       resp = urllib.urlopen("https://issues.apache.org/jira/rest/api/2/search?%s"%params)
       data = json.loads(resp.read())
       if (data.has_key('errorMessages')):
@@ -286,10 +310,8 @@ class JiraIter:
       self.jiras.extend(data['issues'])
 
       needaversion=False
-      for j in versions:
-        v=str(j).replace("-SNAPSHOT","")
-        if v not in releaseVersion:
-          needaversion=True
+      if v not in releaseVersion:
+        needaversion=True
 
       if needaversion is True:
         for i in range(len(data['issues'])):
@@ -351,21 +373,29 @@ class Outputs:
       self.writeKeyRaw(jira.getProject(), line)
 
 def main():
-  parser = OptionParser(usage="usage: %prog --version VERSION [--version VERSION2 ...]",
+  parser = OptionParser(usage="usage: %prog --project PROJECT [--project PROJECT] --version VERSION [--version VERSION2 ...]",
 		epilog=
                "Markdown-formatted CHANGES and RELEASENOTES files will be stored in a directory"
                " named after the highest version provided.")
-  parser.add_option("-v", "--version", dest="versions",
-             action="append", type="string",
-             help="versions in JIRA to include in releasenotes", metavar="VERSION")
-  parser.add_option("-m","--master", dest="master", action="store_true",
-             help="only create the master, merged project files")
   parser.add_option("-i","--index", dest="index", action="store_true",
-             help="build an index file")
-  parser.add_option("-u","--usetoday", dest="usetoday", action="store_true",
-             help="use current date for unreleased versions")
+             default=False, help="build an index file")
+  parser.add_option("-l","--license", dest="license", action="store_false",
+             default=True, help="Add an ASF license")
   parser.add_option("-n","--lint", dest="lint", action="store_true",
              help="use lint flag to exit on failures")
+  parser.add_option("-p", "--project", dest="projects",
+             action="append", type="string",
+             help="projects in JIRA to include in releasenotes", metavar="PROJECT")
+  parser.add_option("-r", "--range", dest="range", action="store_true",
+             default=False, help="Given versions are a range")
+  parser.add_option("-t", "--projecttitle", dest="title",
+             type="string",
+             help="Title to use for the project (default is Apache PROJECT)")
+  parser.add_option("-u","--usetoday", dest="usetoday", action="store_true",
+             default=False, help="use current date for unreleased versions")
+  parser.add_option("-v", "--version", dest="versions",
+             action="append", type="string",
+             help="versions in JIRA to include in releasenotes", metavar="VERSION")
   (options, args) = parser.parse_args()
 
   if (options.versions is None):
@@ -377,169 +407,169 @@ def main():
   if (len(options.versions) <= 0):
     parser.error("At least one version needs to be supplied")
 
-  versions = [ Version(v) for v in options.versions ];
+  projects = options.projects
+
+  if (options.range is True):
+    versions = [ Version(v) for v in GetVersions(options.versions, projects).getlist() ]
+  else:
+    versions = [ Version(v) for v in options.versions ]
   versions.sort();
 
-  maxVersion = str(versions[-1])
+  if (options.title is None):
+    title=projects[0]
+  else:
+    title=options.title
 
-  jlist = JiraIter(versions)
-  version = maxVersion
+  for v in versions:
+    vstr=str(v)
+    jlist = JiraIter(vstr,projects)
 
-  if version in releaseVersion:
-    reldate=releaseVersion[version]
-  elif options.usetoday:
-    reldate=strftime("%Y-%m-%d", gmtime())
-  else:
-    reldate="Unreleased"
+    if vstr in releaseVersion:
+      reldate=releaseVersion[vstr]
+    elif options.usetoday:
+      reldate=strftime("%Y-%m-%d", gmtime())
+    else:
+      reldate="Unreleased"
 
-  if not os.path.exists(version):
-    os.mkdir(version)
+    if not os.path.exists(vstr):
+      os.mkdir(vstr)
 
-  if options.master:
     reloutputs = Outputs("%(ver)s/RELEASENOTES.%(ver)s.md",
       "%(ver)s/RELEASENOTES.%(key)s.%(ver)s.md",
-      [], {"ver":maxVersion, "date":reldate})
+      [], {"ver":v, "date":reldate, "title":title})
     choutputs = Outputs("%(ver)s/CHANGES.%(ver)s.md",
       "%(ver)s/CHANGES.%(key)s.%(ver)s.md",
-      [], {"ver":maxVersion, "date":reldate})
-  else:
-    reloutputs = Outputs("%(ver)s/RELEASENOTES.%(ver)s.md",
-      "%(ver)s/RELEASENOTES.%(key)s.%(ver)s.md",
-      ["HADOOP","HDFS","MAPREDUCE","YARN"], {"ver":maxVersion, "date":reldate})
-    choutputs = Outputs("%(ver)s/CHANGES.%(ver)s.md",
-      "%(ver)s/CHANGES.%(key)s.%(ver)s.md",
-      ["HADOOP","HDFS","MAPREDUCE","YARN"], {"ver":maxVersion, "date":reldate})
-
-  reloutputs.writeAll(asflicense)
-  choutputs.writeAll(asflicense)
-
-  relhead = '# Hadoop %(key)s %(ver)s Release Notes\n\n' \
-    'These release notes cover new developer and user-facing incompatibilities, features, and major improvements.\n\n'
-
-  chhead = '# Hadoop Changelog\n\n' \
-    '## Release %(ver)s - %(date)s\n'\
-    '\n'
-
-  reloutputs.writeAll(relhead)
-  choutputs.writeAll(chhead)
-
-  errorCount=0
-  warningCount=0
-  lintMessage=""
-  incompatlist=[]
-  buglist=[]
-  improvementlist=[]
-  newfeaturelist=[]
-  subtasklist=[]
-  tasklist=[]
-  testlist=[]
-  otherlist=[]
-
-  for jira in sorted(jlist):
-    if jira.getIncompatibleChange():
-      incompatlist.append(jira)
-      if (len(jira.getReleaseNote())==0):
-          warningCount+=1
-
-    if jira.checkVersionString():
-       warningCount+=1
-
-    if jira.checkMissingComponent() or jira.checkMissingAssignee():
-      errorCount+=1
-    elif jira.getType() == "Bug":
-      buglist.append(jira)
-    elif jira.getType() == "Improvement":
-      improvementlist.append(jira)
-    elif jira.getType() == "New Feature":
-      newfeaturelist.append(jira)
-    elif jira.getType() == "Sub-task":
-      subtasklist.append(jira)
-    elif jira.getType() == "Task":
-     tasklist.append(jira)
-    elif jira.getType() == "Test":
-      testlist.append(jira)
-    else:
-       otherlist.append(jira)
-
-    line = '* [%s](https://issues.apache.org/jira/browse/%s) | *%s* | **%s**\n' \
-        % (notableclean(jira.getId()), notableclean(jira.getId()), notableclean(jira.getPriority()),
-           notableclean(jira.getSummary()))
-
-    if (jira.getIncompatibleChange()) and (len(jira.getReleaseNote())==0):
-      reloutputs.writeKeyRaw(jira.getProject(),"\n---\n\n")
-      reloutputs.writeKeyRaw(jira.getProject(), line)
-      line ='\n**WARNING: No release note provided for this incompatible change.**\n\n'
-      lintMessage += "\nWARNING: incompatible change %s lacks release notes." % (notableclean(jira.getId()))
-      reloutputs.writeKeyRaw(jira.getProject(), line)
-
-    if jira.checkVersionString():
-        lintMessage += "\nWARNING: Version string problem for %s " % jira.getId()
-
-    if (jira.checkMissingComponent() or jira.checkMissingAssignee()):
-        errorMessage=[]
-        jira.checkMissingComponent() and errorMessage.append("component")
-        jira.checkMissingAssignee() and errorMessage.append("assignee")
-        lintMessage += "\nERROR: missing %s for %s " %  (" and ".join(errorMessage) , jira.getId())
-
-    if (len(jira.getReleaseNote())>0):
-      reloutputs.writeKeyRaw(jira.getProject(),"\n---\n\n")
-      reloutputs.writeKeyRaw(jira.getProject(), line)
-      line ='\n%s\n\n' % (tableclean(jira.getReleaseNote()))
-      reloutputs.writeKeyRaw(jira.getProject(), line)
-
-  if (options.lint is True):
-      print lintMessage
-      print "======================================="
-      print "Error:%d, Warning:%d \n" % (errorCount, warningCount)
-
-      if (errorCount>0):
-          cleanOutputDir(version)
-          sys.exit(1)
-
-  reloutputs.writeAll("\n\n")
-  reloutputs.close()
-
-  choutputs.writeAll("### INCOMPATIBLE CHANGES:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(incompatlist)
-
-  choutputs.writeAll("\n\n### NEW FEATURES:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(newfeaturelist)
-
-  choutputs.writeAll("\n\n### IMPROVEMENTS:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(improvementlist)
-
-  choutputs.writeAll("\n\n### BUG FIXES:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(buglist)
-
-  choutputs.writeAll("\n\n### TESTS:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(testlist)
-
-  choutputs.writeAll("\n\n### SUB-TASKS:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(subtasklist)
-
-  choutputs.writeAll("\n\n### OTHER:\n\n")
-  choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
-  choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
-  choutputs.writeList(otherlist)
-  choutputs.writeList(tasklist)
-
-  choutputs.writeAll("\n\n")
-  choutputs.close()
+      [], {"ver":v, "date":reldate, "title":title})
+
+    if (options.license is True):
+      reloutputs.writeAll(asflicense)
+      choutputs.writeAll(asflicense)
+
+    relhead = '# %(title)s %(key)s %(ver)s Release Notes\n\n' \
+      'These release notes cover new developer and user-facing incompatibilities, features, and major improvements.\n\n'
+    chhead = '# %(title)s Changelog\n\n' \
+      '## Release %(ver)s - %(date)s\n'\
+      '\n'
+
+    reloutputs.writeAll(relhead)
+    choutputs.writeAll(chhead)
+    errorCount=0
+    warningCount=0
+    lintMessage=""
+    incompatlist=[]
+    buglist=[]
+    improvementlist=[]
+    newfeaturelist=[]
+    subtasklist=[]
+    tasklist=[]
+    testlist=[]
+    otherlist=[]
+
+    for jira in sorted(jlist):
+      if jira.getIncompatibleChange():
+        incompatlist.append(jira)
+        if (len(jira.getReleaseNote())==0):
+            warningCount+=1
+
+      if jira.checkVersionString():
+         warningCount+=1
+
+      if jira.checkMissingComponent() or jira.checkMissingAssignee():
+        errorCount+=1
+      elif jira.getType() == "Bug":
+        buglist.append(jira)
+      elif jira.getType() == "Improvement":
+        improvementlist.append(jira)
+      elif jira.getType() == "New Feature":
+        newfeaturelist.append(jira)
+      elif jira.getType() == "Sub-task":
+        subtasklist.append(jira)
+      elif jira.getType() == "Task":
+       tasklist.append(jira)
+      elif jira.getType() == "Test":
+        testlist.append(jira)
+      else:
+         otherlist.append(jira)
+
+      line = '* [%s](https://issues.apache.org/jira/browse/%s) | *%s* | **%s**\n' \
+          % (notableclean(jira.getId()), notableclean(jira.getId()), notableclean(jira.getPriority()),
+             notableclean(jira.getSummary()))
+
+      if (jira.getIncompatibleChange()) and (len(jira.getReleaseNote())==0):
+        reloutputs.writeKeyRaw(jira.getProject(),"\n---\n\n")
+        reloutputs.writeKeyRaw(jira.getProject(), line)
+        line ='\n**WARNING: No release note provided for this incompatible change.**\n\n'
+        lintMessage += "\nWARNING: incompatible change %s lacks release notes." % (notableclean(jira.getId()))
+        reloutputs.writeKeyRaw(jira.getProject(), line)
+
+      if jira.checkVersionString():
+          lintMessage += "\nWARNING: Version string problem for %s " % jira.getId()
+
+      if (jira.checkMissingComponent() or jira.checkMissingAssignee()):
+          errorMessage=[]
+          jira.checkMissingComponent() and errorMessage.append("component")
+          jira.checkMissingAssignee() and errorMessage.append("assignee")
+          lintMessage += "\nERROR: missing %s for %s " %  (" and ".join(errorMessage) , jira.getId())
+
+      if (len(jira.getReleaseNote())>0):
+        reloutputs.writeKeyRaw(jira.getProject(),"\n---\n\n")
+        reloutputs.writeKeyRaw(jira.getProject(), line)
+        line ='\n%s\n\n' % (tableclean(jira.getReleaseNote()))
+        reloutputs.writeKeyRaw(jira.getProject(), line)
+
+    if (options.lint is True):
+        print lintMessage
+        print "======================================="
+        print "Error:%d, Warning:%d \n" % (errorCount, warningCount)
+
+        if (errorCount>0):
+            cleanOutputDir(version)
+            sys.exit(1)
+
+    reloutputs.writeAll("\n\n")
+    reloutputs.close()
+
+    choutputs.writeAll("### INCOMPATIBLE CHANGES:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(incompatlist)
+
+    choutputs.writeAll("\n\n### NEW FEATURES:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(newfeaturelist)
+
+    choutputs.writeAll("\n\n### IMPROVEMENTS:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(improvementlist)
+
+    choutputs.writeAll("\n\n### BUG FIXES:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(buglist)
+
+    choutputs.writeAll("\n\n### TESTS:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(testlist)
+
+    choutputs.writeAll("\n\n### SUB-TASKS:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(subtasklist)
+
+    choutputs.writeAll("\n\n### OTHER:\n\n")
+    choutputs.writeAll("| JIRA | Summary | Priority | Component | Reporter | Contributor |\n")
+    choutputs.writeAll("|:---- |:---- | :--- |:---- |:---- |:---- |\n")
+    choutputs.writeList(otherlist)
+    choutputs.writeList(tasklist)
+
+    choutputs.writeAll("\n\n")
+    choutputs.close()
 
   if options.index:
-    buildindex(options.master)
+    buildindex(title,options.license)
 
 if __name__ == "__main__":
   main()