summaryrefslogtreecommitdiff
path: root/contrib/get_hash_for_release
blob: 9b3497c718f192075e7ccc6c054e93c507b84631 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/bin/bash
# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# The "get_hash_for_release" command can be used in one of two forms:
#  - It can be used to return the hash associated with the project in
#    the current directory:
#
#      ~/chromiumos/chromite$ get_hash_for_release 6822.0.0
#      0b325183cf2eee7f93d7d631a8639c089f4a2d4f
#      # This is the hash of the "chromite" package for release 6822.0.0
#
#  - It can indicate what is the earliest release where a given hash
#    appeared:
#
#     ~/chromiumos/chromite$ get_hash_for_release R41 \
#         8eba257003357ca945528fb93dadd2c4d16b7d11
#     Oldest release with 8eba257003357ca945528fb93dadd2c4d16b7d11 is 6674.0.0


fetch_manifests() {
  temp_dir=/tmp/chrome_manifest_temp
  if [[ ! -d "${temp_dir}" ]] ; then
    mkdir -p "${temp_dir}"
    local git_server="https://chrome-internal.googlesource.com"
    git clone -q --depth 1 --single-branch \
        "${git_server}/chromeos/manifest-versions" "${temp_dir}"
  else
    (cd "${temp_dir}" && git pull -q)
  fi
}

cleanup_manifests() {
  if [[ -d "${temp_dir}" ]] ; then
    rm -rf "${temp_dir}"
  fi
}

is_child_release() {
  # Release numbers are stated in a set of dotted integers.
  # 2.0.0.0 is a child of 1.0.0.0 (later release)
  # 2.1.0.0 is a child of 2.0.0.0 (new branch)
  # 3.0.0.0 is a child of 2.0.0.0 but not 2.1.0.0 since 2.1 branched from 2.0.
  # 3.0.1.0 isn't really valid (branches are left aligned) but we ignore this.

  local child
  local parent
  IFS='.' read -a child <<< "$1"
  IFS='.' read -a parent <<< "$2"
  if [[ ${#child[@]} -ne ${#parent[@]} ]] ; then
    return 1
  fi

  local must_be_root
  for idx in $(seq 0 $((${#child[@]} - 1))); do
    local parent_num="${parent[idx]}"
    [[ -n "${must_be_root}" && "$parent_num" != "0" ]] && return 1
    local child_num="${child[idx]}"
    [[ "${parent_num}" > "${child_num}" ]] && return 1
    [[ "${parent_num}" < "${child_num}" ]] && must_be_root=1
  done
  return 0
}

get_project_info() {
  repo info . 2>/dev/null | egrep '^(Project|Current revision):' | cut -f2 -d:
}

get_revision() {
  local release="$1"
  local revision="$2"
  grep "${project}.*upstream=.*${branch}" \
      ${temp_dir}/buildspecs/$release/${revision}.xml |
      sed -e 's/ *<project.*revision="\([^"]*\)".*/\1/' \
          -e 's/^.*\/\([0-9.]*\)\.xml:/\1 : /'
}

get_hash_for_release() {
  get_revision '*' "${revision}"
}

get_release_for_hash() {
  local release="${revision:1}"
  local -a all_revs=($(ls "${temp_dir}/buildspecs/${release}" |
                       sort -Vr | sed -e 's/\.xml$//'))
  latest_rev=$(basename $(cd "${temp_dir}/buildspecs/${release}" &&
                          git log -n1 --name-only --oneline --grep release . |
                          grep -v ' ' | sort -V | tail -1 |
                          sed -e 's/\.xml$//'))
  revs=()
  for rev in "${all_revs[@]}"; do
    is_child_release "${latest_rev}" "${rev}" && revs+=("${rev}")
  done
  last_released_hash=$(get_revision "${release}" "${latest_rev}" |
                       awk '{print $1}')
  if [[ -z "${last_released_hash}" ]] ; then
    echo "Huh?  Can't find hash for ${latest_rev}"
    return
  fi
  local -a hashes
  found=''
  for search_size in 10 100 1000 10000; do
    hashes=($(git log --pretty=format:%H -n "${search_size}" \
              "${last_released_hash}"))
    if echo "${hashes[*]}" | grep -q $hash; then
      found=1
      break
    fi
  done
  if [[ -z "${found}" ]] ; then
    echo "Perhaps ${hash} was never in release ${release}?"
    return
  fi
  # Pop all hashes after the one we care about.
  while [[ "${hashes[-1]}" != "${hash}" ]] ; do
    unset hashes[${#hashes[@]}-1]
  done
  oldest_release="${latest_rev}"
  idx=1
  while [[ $idx -lt ${#revs[@]} ]]; do
    rev="${revs[idx]}"
    hash_for_rev=$(get_revision "${release}" "${rev}" |
                   awk '{print $1}')
    if ! echo "${hashes[*]}" | grep -q $hash_for_rev; then
      break
    fi
    oldest_release="${rev}"
    idx=$(( idx + 1 ))
  done
  echo "Oldest release with ${hash} is ${oldest_release}"
}

main() {
  revision="${1}"
  if [[ -z "${revision}"  ]] ; then
    echo "Usage: $0 <revision> [hash]"
    exit 0
  fi

  if expr "${revision}" : '[MR]' > /dev/null; then
    hash="${2}"
    shift
  fi

  project_info=($(get_project_info))

  if [[ "${#project_info[@]}" < 2 ]] ; then
    echo "Couldn't get project info (are you in a repo directory?)"
    exit 0
  fi

  project="${project_info[0]}"
  branch="$(echo ${project_info[1]} | cut -d/ -f3)"
  if [[ "${branch}" == "master" ]] ; then
    branch=""
  elif [[ "${branch}" == "chromeos-3.4" ]] ; then
    # Hack for old releases of chromeos-kernel.
    branch='\.[4B]"'
  fi

  fetch_manifests

  if [[ -z "${hash}" ]] ; then
    get_hash_for_release
  else
    get_release_for_hash
  fi

  #cleanup_manifests
}

main "$@"