1#!/bin/bash
2
3SELF=$(basename "${0}")
4DEFAULT_TAG="jdk17u/jdk-17.0.6-ga"
5SUPPORTED_TAGS="jdk7u/jdk7u40-b60"
6SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk8u/jdk8u121-b13"
7SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk8u/jdk8u60-b31"
8SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk9/jdk-9+181"
9SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk11u/jdk-11+28"
10SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk11u/jdk-11.0.13-ga"
11SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk17u/jdk-17.0.2-ga"
12SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk17u/jdk-17.0.5-ga"
13SUPPORTED_TAGS="${SUPPORTED_TAGS} jdk17u/jdk-17.0.6-ga"
14
15
16USAGE=$(cat << EndOfUsage
17Usage:
18  ${SELF} [-b <bug_number>] [-t <upstream_tag>] <package_name> <package_name> ...
19  For example:
20    ${SELF} -b 123456 -t jdk17u/jdk-17.0.6-ga java.util.concurrent java.util.concurrent.atomic
21    ${SELF} java.util.concurrent.atomic -c AtomicInteger,AtomicBoolean,AtomicLong
22    ${SELF} java.util.concurrent.atomic -c AtomicInteger -c AtomicBoolean -c AtomicLong
23
24Possible arguments:
25  -h|--help - print help and exit
26  -t|--tag - the upstream tag to merge to; default: ${DEFAULT_TAG} or
27             OJLUNI_MERGE_TARGET (if defined)
28  -c|--classes - list of classes from the package to be processed; this is useful if only
29                 some classes from a package are to be merged; only a single
30                 package must be specified; can be provided as a comma-separated
31                 list, or repeated -c arguments
32  -b|--bug - the bug number to use in the commit message; if not defined it will
33             be picked up from the libcore branch name (for example
34             "b-12345-oj-merge" -> "-b 12345")
35
36The supported upstream tags are:
37  $(echo ${SUPPORTED_TAGS} | sed 's/ /\n  /g')
38EndOfUsage
39)
40
41HELP=$(cat << EndOfHelp
42Merges one or more packages from an upstream branch.
43
44This will use the correct form of add/modify based on what is already stored in
45libcore/EXPECTED_UPSTREAM.  Also it will find new files in the new version of
46the upstream package and add those as well.
47
48${USAGE}
49EndOfHelp
50)
51
52BUG=""
53PACKAGES=()
54TAG="${OJLUNI_MERGE_TARGET:-"$DEFAULT_TAG"}"
55CLASSES=()
56
57function die()
58{
59  echo -e ${1}
60  if [[ -n "${2}" ]]
61  then
62    echo -e ""
63    echo -e "${USAGE}"
64  fi
65  exit 1
66}
67
68function validate_tag
69{
70  for expected in ${SUPPORTED_TAGS}
71  do
72    if [[ "${TAG}" == "${expected}" ]]
73    then
74      return
75    fi
76  done
77  die "Unknown tag: ${TAG}" "y"
78}
79
80function setup_env
81{
82  if [[ -z "${ANDROID_BUILD_TOP}" ]]
83  then
84    die "ANDROID_BUILD_TOP not found. You need to run lunch first."
85  fi
86
87  shopt -s expand_aliases
88  source "${ANDROID_BUILD_TOP}/libcore/tools/expected_upstream/install_tools.sh"
89}
90
91while [[ $# -gt 0 ]]; do
92  case ${1} in
93    -h|--help)
94      echo "${HELP}"
95      exit 0
96      ;;
97    -b|--bug)
98      BUG="${2}"
99      shift
100      ;;
101    -t|--tag)
102      TAG="${2}"
103      shift
104      ;;
105    -c|--classes)
106      classes=$(echo "${2}" | sed 's/,/ /g')
107      for class in $(echo "${2}" | sed 's/,/ /g')
108      do
109        CLASSES+=(${class})
110      done
111      shift
112      ;;
113    *)
114      PACKAGES+=(${1})
115      ;;
116  esac
117  shift
118done
119
120if [[ ${#PACKAGES[@]} -eq 0 ]]
121then
122  die "You need to specify at least one package to merge." "y"
123elif [[ ${#CLASSES[@]} -gt 0 && ${#PACKAGES[@]} -gt 1 ]]
124then
125  die "The -c|--classes argument can only be provided with a single package" "y"
126fi
127
128setup_env
129validate_tag
130
131if [[ -z "${BUG}" ]]
132then
133  pushd "${ANDROID_BUILD_TOP}/libcore"
134  BUG=$(git branch --show-current | grep -E -o "\<b\>[-/][0-9]+-" | grep -E -o "[0-9]+")
135  popd
136fi
137
138function merge-class
139{
140  local method="${1}"
141  local name="${2}"
142  local version="${3}"
143
144  local first_arg="${name}"
145  local second_arg="${version}"
146
147  if [[ "${method}" == "add" ]]
148  then
149    first_arg="${version}"
150    second_arg="${name}"
151  fi
152  echo ojluni_modify_expectation "${method}" "${first_arg}" "${second_arg}"
153  ojluni_modify_expectation "${method}" "${first_arg}" "${second_arg}" || \
154    die "Failed to modify expectation file for ${name}"
155}
156
157function do-merge
158{
159  local package="${1}"
160  local bug="${2}"
161
162  if [[ -n "${bug}" ]]
163  then
164    echo ojluni_merge_to_main -b "${bug}"
165    ojluni_merge_to_main -b "${bug}" || die "Failed to merge ${package} to master"
166  else
167    echo ojluni_merge_to_main
168    ojluni_merge_to_main || die "Failed to merge ${package} to master"
169  fi
170}
171
172function is-class-in-expected-upstream
173{
174  local package_path="${1}"
175  local class_name="${2}"
176  local class_path="ojluni/src/main/java/${package_path}/${class_name}\.java"
177  grep "${class_path}" "${ANDROID_BUILD_TOP}/libcore/EXPECTED_UPSTREAM"
178}
179
180function get-package-path
181{
182  local package="${1}"
183  echo "${package}" | sed --sandbox 's/\./\//'g
184}
185
186function ojluni-merge-package
187{
188  local package="${1}"
189  local version="${2}"
190  local bug="${3}"
191  local package_path=$(get-package-path "${package}")
192  local package_full_path="${ANDROID_BUILD_TOP}/libcore/ojluni/src/main/java/${package_path}"
193
194  pushd "${ANDROID_BUILD_TOP}/libcore"
195
196  for f in $(ls "${package_full_path}"/*.java)
197  do
198    local class_name=$(basename -s .java ${f})
199    local in_expected_upstream=$(is-class-in-expected-upstream "${package_path}" "${class_name}")
200    if [[ -n "${in_expected_upstream}" ]]
201    then
202      merge-class modify "${package}.${class_name}" "${version}"
203    else
204      merge-class add "${package}.${class_name}" "${version}"
205    fi
206  done
207
208  local version_id=$(echo "${version}" | grep -oE "^[^/]+")
209  local branch="aosp/upstream-open${version_id}"
210  local new_classes=$(git diff --name-only --diff-filter=D "${branch}" -- \
211    "src/java.base/share/classes/${package_path}" \
212    "ojluni/src/main/java/${package_path}")
213
214  for f in ${new_classes}
215  do
216    local class_name=$(basename -s .java ${f})
217    local class_path="ojluni/src/main/java/${package_path}/${class_name}\.java"
218    merge-class add "${package}.${class_name}" "${version}"
219  done
220
221  do-merge "${package}" "${bug}"
222
223  popd
224}
225
226function ojluni-merge-class
227{
228  local package="${1}"
229  local class="${2}"
230  local version="${3}"
231  local package_path=$(get-package-path "${package}")
232  local in_expected_upstream=$(is-class-in-expected-upstream "${package_path}" "${class}")
233  if [[ -n "${in_expected_upstream}" ]]
234  then
235    merge-class modify "${package}.${class}" "${version}"
236  else
237    merge-class add "${package}.${class}" "${version}"
238  fi
239}
240
241if [[ ${#CLASSES[@]} -eq 0 ]]
242then
243  for package in ${PACKAGES[@]}
244  do
245    echo "Merging '${package}' from ${TAG}"
246    ojluni-merge-package "${package}" "${TAG}" "${BUG}"
247  done
248elif [[ ${#PACKAGES[@]} -eq 1 ]]
249then
250  package=${PACKAGES[0]}
251  for class in ${CLASSES[@]}
252  do
253    echo "Merging ${package}.${class}"
254    ojluni-merge-class "${package}" "${class}" "${TAG}"
255  done
256  do-merge "${package}" "${BUG}"
257fi
258