{"id":17465,"url":"https://patchwork.libcamera.org/api/1.1/patches/17465/?format=json","web_url":"https://patchwork.libcamera.org/patch/17465/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20220929143626.3100668-3-kieran.bingham@ideasonboard.com>","date":"2022-09-29T14:36:24","name":"[libcamera-devel,2/4] utils: semver: Add version helper","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"4cafa453660bc0e2d5ce677b537ac0d6bab3d9b1","submitter":{"id":4,"url":"https://patchwork.libcamera.org/api/1.1/people/4/?format=json","name":"Kieran Bingham","email":"kieran.bingham@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/17465/mbox/","series":[{"id":3514,"url":"https://patchwork.libcamera.org/api/1.1/series/3514/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=3514","date":"2022-09-29T14:36:22","name":"Add release infrastructure","version":1,"mbox":"https://patchwork.libcamera.org/series/3514/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/17465/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/17465/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 71F2FC0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 29 Sep 2022 14:36:40 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B93496239B;\n\tThu, 29 Sep 2022 16:36:37 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 071D162384\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 29 Sep 2022 16:36:35 +0200 (CEST)","from Monstersaurus.local\n\t(cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 825896DB;\n\tThu, 29 Sep 2022 16:36:34 +0200 (CEST)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1664462197;\n\tbh=W9mNoqhQYFhWItqIHxbM81MzpkzJYJH+KRNu6PB68sA=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=izfZHXGu1TJvGfjg8PbHSTmS8KcFIF8EBwyVNF66Xxy+Kv25qcQq7r97T2tl+IRYU\n\tLcxBr7z22RasNdeJhuD/TsCxZQXQ80Zc4dRCEDbiN1qbjG/XINwsKOGiTkvEclmb8p\n\tngAJWNgwcNUuD7JOLzDY+2V6YDun1TdtvszIQyLupCExylfmFN6dk23Dq85p1+Chv7\n\tsh3qb6qJA9YQz7oChXQlSyXtYS4bJIgiPHIsGzjj2u2an/D5qEdu24WZIPRKtABizs\n\tIp8eqaFiWX45C5Gdu3MG1dUX1nrPsgW4l8mJN4k1vG7i9plXhFy2tsUkKcTqL39paM\n\tWzePqFsimzhrA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1664462194;\n\tbh=W9mNoqhQYFhWItqIHxbM81MzpkzJYJH+KRNu6PB68sA=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=OeN8nvyPLASEFSF142sP7+FgWQGK8qDu6CkmvCI8sFf8i7stWhJ9/O9/xZiSHCiVQ\n\tl21fU9OEeRJQ6YikLu7eilM8qgAPUJBzI+xoTpg9xeXJJhoS6RIZm+dyuc+UEYu6Rd\n\tBVsyy2m35TmFLy+9XlaGd5OQgsORO/Ffi8ky4Krk="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"OeN8nvyP\"; dkim-atps=neutral","To":"libcamera devel <libcamera-devel@lists.libcamera.org>","Date":"Thu, 29 Sep 2022 15:36:24 +0100","Message-Id":"<20220929143626.3100668-3-kieran.bingham@ideasonboard.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20220929143626.3100668-1-kieran.bingham@ideasonboard.com>","References":"<20220929143626.3100668-1-kieran.bingham@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 2/4] utils: semver: Add version helper","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Kieran Bingham via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Provide the semver utility from [0] to make use of it with our\nversioning and release scripts.\n\n[0] https://github.com/fsaintjacques/semver-tool\n\nSigned-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n---\n utils/semver | 419 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 419 insertions(+)\n create mode 100755 utils/semver","diff":"diff --git a/utils/semver b/utils/semver\nnew file mode 100755\nindex 000000000000..5b25f40ba48c\n--- /dev/null\n+++ b/utils/semver\n@@ -0,0 +1,419 @@\n+#!/usr/bin/env bash\n+\n+set -o errexit -o nounset -o pipefail\n+\n+NAT='0|[1-9][0-9]*'\n+ALPHANUM='[0-9]*[A-Za-z-][0-9A-Za-z-]*'\n+IDENT=\"$NAT|$ALPHANUM\"\n+FIELD='[0-9A-Za-z-]+'\n+\n+SEMVER_REGEX=\"\\\n+^[vV]?\\\n+($NAT)\\\\.($NAT)\\\\.($NAT)\\\n+(\\\\-(${IDENT})(\\\\.(${IDENT}))*)?\\\n+(\\\\+${FIELD}(\\\\.${FIELD})*)?$\"\n+\n+PROG=semver\n+PROG_VERSION=\"3.3.0\"\n+\n+USAGE=\"\\\n+Usage:\n+  $PROG bump (major|minor|patch|release|prerel [<prerel>]|build <build>) <version>\n+  $PROG compare <version> <other_version>\n+  $PROG diff <version> <other_version>\n+  $PROG get (major|minor|patch|release|prerel|build) <version>\n+  $PROG validate <version>\n+  $PROG --help\n+  $PROG --version\n+\n+Arguments:\n+  <version>  A version must match the following regular expression:\n+             \\\"${SEMVER_REGEX}\\\"\n+             In English:\n+             -- The version must match X.Y.Z[-PRERELEASE][+BUILD]\n+                where X, Y and Z are non-negative integers.\n+             -- PRERELEASE is a dot separated sequence of non-negative integers and/or\n+                identifiers composed of alphanumeric characters and hyphens (with\n+                at least one non-digit). Numeric identifiers must not have leading\n+                zeros. A hyphen (\\\"-\\\") introduces this optional part.\n+             -- BUILD is a dot separated sequence of identifiers composed of alphanumeric\n+                characters and hyphens. A plus (\\\"+\\\") introduces this optional part.\n+\n+  <other_version>  See <version> definition.\n+\n+  <prerel>  A string as defined by PRERELEASE above. Or, it can be a PRERELEASE\n+            prototype string (or empty) followed by a dot.\n+\n+  <build>   A string as defined by BUILD above.\n+\n+Options:\n+  -v, --version          Print the version of this tool.\n+  -h, --help             Print this help message.\n+\n+Commands:\n+  bump      Bump by one of major, minor, patch; zeroing or removing\n+            subsequent parts. \\\"bump prerel\\\" sets the PRERELEASE part and\n+            removes any BUILD part. A trailing dot in the <prerel> argument\n+            introduces an incrementing numeric field which is added or\n+            bumped. If no <prerel> argument is provided, an incrementing numeric\n+            field is introduced/bumped. \\\"bump build\\\" sets the BUILD part.\n+            \\\"bump release\\\" removes any PRERELEASE or BUILD parts.\n+            The bumped version is written to stdout.\n+\n+  compare   Compare <version> with <other_version>, output to stdout the\n+            following values: -1 if <other_version> is newer, 0 if equal, 1 if\n+            older. The BUILD part is not used in comparisons.\n+\n+  diff      Compare <version> with <other_version>, output to stdout the\n+            difference between two versions by the release type (MAJOR, MINOR,\n+            PATCH, PRERELEASE, BUILD).\n+\n+  get       Extract given part of <version>, where part is one of major, minor,\n+            patch, prerel, build, or release.\n+\n+  validate  Validate if <version> follows the SEMVER pattern (see <version>\n+            definition). Print 'valid' to stdout if the version is valid, otherwise\n+            print 'invalid'.\n+\n+See also:\n+  https://semver.org -- Semantic Versioning 2.0.0\"\n+\n+function error {\n+  echo -e \"$1\" >&2\n+  exit 1\n+}\n+\n+function usage_help {\n+  error \"$USAGE\"\n+}\n+\n+function usage_version {\n+  echo -e \"${PROG}: $PROG_VERSION\"\n+  exit 0\n+}\n+\n+function validate_version {\n+  local version=$1\n+  if [[ \"$version\" =~ $SEMVER_REGEX ]]; then\n+    # if a second argument is passed, store the result in var named by $2\n+    if [ \"$#\" -eq \"2\" ]; then\n+      local major=${BASH_REMATCH[1]}\n+      local minor=${BASH_REMATCH[2]}\n+      local patch=${BASH_REMATCH[3]}\n+      local prere=${BASH_REMATCH[4]}\n+      local build=${BASH_REMATCH[8]}\n+      eval \"$2=(\\\"$major\\\" \\\"$minor\\\" \\\"$patch\\\" \\\"$prere\\\" \\\"$build\\\")\"\n+    else\n+      echo \"$version\"\n+    fi\n+  else\n+    error \"version $version does not match the semver scheme 'X.Y.Z(-PRERELEASE)(+BUILD)'. See help for more information.\"\n+  fi\n+}\n+\n+function is_nat {\n+    [[ \"$1\" =~ ^($NAT)$ ]]\n+}\n+\n+function is_null {\n+    [ -z \"$1\" ]\n+}\n+\n+function order_nat {\n+    [ \"$1\" -lt \"$2\" ] && { echo -1 ; return ; }\n+    [ \"$1\" -gt \"$2\" ] && { echo 1 ; return ; }\n+    echo 0\n+}\n+\n+function order_string {\n+    [[ $1 < $2 ]] && { echo -1 ; return ; }\n+    [[ $1 > $2 ]] && { echo 1 ; return ; }\n+    echo 0\n+}\n+\n+# given two (named) arrays containing NAT and/or ALPHANUM fields, compare them\n+# one by one according to semver 2.0.0 spec. Return -1, 0, 1 if left array ($1)\n+# is less-than, equal, or greater-than the right array ($2).  The longer array\n+# is considered greater-than the shorter if the shorter is a prefix of the longer.\n+#\n+function compare_fields {\n+    local l=\"$1[@]\"\n+    local r=\"$2[@]\"\n+    local leftfield=( \"${!l}\" )\n+    local rightfield=( \"${!r}\" )\n+    local left\n+    local right\n+\n+    local i=$(( -1 ))\n+    local order=$(( 0 ))\n+\n+    while true\n+    do\n+        [ $order -ne 0 ] && { echo $order ; return ; }\n+\n+        : $(( i++ ))\n+        left=\"${leftfield[$i]}\"\n+        right=\"${rightfield[$i]}\"\n+\n+        is_null \"$left\" && is_null \"$right\" && { echo 0  ; return ; }\n+        is_null \"$left\"                     && { echo -1 ; return ; }\n+                           is_null \"$right\" && { echo 1  ; return ; }\n+\n+        is_nat \"$left\" &&  is_nat \"$right\" && { order=$(order_nat \"$left\" \"$right\") ; continue ; }\n+        is_nat \"$left\"                     && { echo -1 ; return ; }\n+                           is_nat \"$right\" && { echo 1  ; return ; }\n+                                              { order=$(order_string \"$left\" \"$right\") ; continue ; }\n+    done\n+}\n+\n+# shellcheck disable=SC2206     # checked by \"validate\"; ok to expand prerel id's into array\n+function compare_version {\n+  local order\n+  validate_version \"$1\" V\n+  validate_version \"$2\" V_\n+\n+  # compare major, minor, patch\n+\n+  local left=( \"${V[0]}\" \"${V[1]}\" \"${V[2]}\" )\n+  local right=( \"${V_[0]}\" \"${V_[1]}\" \"${V_[2]}\" )\n+\n+  order=$(compare_fields left right)\n+  [ \"$order\" -ne 0 ] && { echo \"$order\" ; return ; }\n+\n+  # compare pre-release ids when M.m.p are equal\n+\n+  local prerel=\"${V[3]:1}\"\n+  local prerel_=\"${V_[3]:1}\"\n+  local left=( ${prerel//./ } )\n+  local right=( ${prerel_//./ } )\n+\n+  # if left and right have no pre-release part, then left equals right\n+  # if only one of left/right has pre-release part, that one is less than simple M.m.p\n+\n+  [ -z \"$prerel\" ] && [ -z \"$prerel_\" ] && { echo 0  ; return ; }\n+  [ -z \"$prerel\" ]                      && { echo 1  ; return ; }\n+                      [ -z \"$prerel_\" ] && { echo -1 ; return ; }\n+\n+  # otherwise, compare the pre-release id's\n+\n+  compare_fields left right\n+}\n+\n+# render_prerel -- return a prerel field with a trailing numeric string\n+#                  usage: render_prerel numeric [prefix-string]\n+#\n+function render_prerel {\n+    if [ -z \"$2\" ]\n+    then\n+        echo \"${1}\"\n+    else\n+        echo \"${2}${1}\"\n+    fi\n+}\n+\n+# extract_prerel -- extract prefix and trailing numeric portions of a pre-release part\n+#                   usage: extract_prerel prerel prerel_parts\n+#                   The prefix and trailing numeric parts are returned in \"prerel_parts\".\n+#\n+PREFIX_ALPHANUM='[.0-9A-Za-z-]*[.A-Za-z-]'\n+DIGITS='[0-9][0-9]*'\n+EXTRACT_REGEX=\"^(${PREFIX_ALPHANUM})*(${DIGITS})$\"\n+\n+function extract_prerel {\n+    local prefix; local numeric;\n+\n+    if [[ \"$1\" =~ $EXTRACT_REGEX ]]\n+    then                                        # found prefix and trailing numeric parts\n+        prefix=\"${BASH_REMATCH[1]}\"\n+        numeric=\"${BASH_REMATCH[2]}\"\n+    else                                        # no numeric part\n+        prefix=\"${1}\"\n+        numeric=\n+    fi\n+\n+    eval \"$2=(\\\"$prefix\\\" \\\"$numeric\\\")\"\n+}\n+\n+# bump_prerel -- return the new pre-release part based on previous pre-release part\n+#                and prototype for bump\n+#                usage: bump_prerel proto previous\n+#\n+function bump_prerel {\n+    local proto; local prev_prefix; local prev_numeric;\n+\n+    # case one: no trailing dot in prototype => simply replace previous with proto\n+    if [[ ! ( \"$1\" =~ \\.$ ) ]]\n+    then\n+        echo \"$1\"\n+        return\n+    fi\n+\n+    proto=\"${1%.}\"                              # discard trailing dot marker from prototype\n+\n+    extract_prerel \"${2#-}\" prerel_parts        # extract parts of previous pre-release\n+#   shellcheck disable=SC2154\n+    prev_prefix=\"${prerel_parts[0]}\"\n+    prev_numeric=\"${prerel_parts[1]}\"\n+\n+    # case two: bump or append numeric to previous pre-release part\n+    if [ \"$proto\" == \"+\" ]                      # dummy \"+\" indicates no prototype argument provided\n+    then\n+        if [ -n \"$prev_numeric\" ]\n+        then\n+            : $(( ++prev_numeric ))             # previous pre-release is already numbered, bump it\n+            render_prerel \"$prev_numeric\" \"$prev_prefix\"\n+        else\n+            render_prerel 1 \"$prev_prefix\"      # append starting number\n+        fi\n+        return\n+    fi\n+\n+    # case three: set, bump, or append using prototype prefix\n+    if [  \"$prev_prefix\" != \"$proto\" ]\n+    then\n+        render_prerel 1 \"$proto\"                # proto not same pre-release; set and start at '1'\n+    elif [ -n \"$prev_numeric\" ]\n+    then\n+        : $(( ++prev_numeric ))                 # pre-release is numbered; bump it\n+        render_prerel \"$prev_numeric\" \"$prev_prefix\"\n+    else\n+        render_prerel 1 \"$prev_prefix\"          # start pre-release at number '1'\n+    fi\n+}\n+\n+function command_bump {\n+  local new; local version; local sub_version; local command;\n+\n+  case $# in\n+    2) case $1 in\n+        major|minor|patch|prerel|release) command=$1; sub_version=\"+.\"; version=$2;;\n+        *) usage_help;;\n+       esac ;;\n+    3) case $1 in\n+        prerel|build) command=$1; sub_version=$2 version=$3 ;;\n+        *) usage_help;;\n+       esac ;;\n+    *) usage_help;;\n+  esac\n+\n+  validate_version \"$version\" parts\n+  # shellcheck disable=SC2154\n+  local major=\"${parts[0]}\"\n+  local minor=\"${parts[1]}\"\n+  local patch=\"${parts[2]}\"\n+  local prere=\"${parts[3]}\"\n+  local build=\"${parts[4]}\"\n+\n+  case \"$command\" in\n+    major) new=\"$((major + 1)).0.0\";;\n+    minor) new=\"${major}.$((minor + 1)).0\";;\n+    patch) new=\"${major}.${minor}.$((patch + 1))\";;\n+    release) new=\"${major}.${minor}.${patch}\";;\n+    prerel) new=$(validate_version \"${major}.${minor}.${patch}-$(bump_prerel \"$sub_version\" \"$prere\")\");;\n+    build) new=$(validate_version \"${major}.${minor}.${patch}${prere}+${sub_version}\");;\n+    *) usage_help ;;\n+  esac\n+\n+  echo \"$new\"\n+  exit 0\n+}\n+\n+function command_compare {\n+  local v; local v_;\n+\n+  case $# in\n+    2) v=$(validate_version \"$1\"); v_=$(validate_version \"$2\") ;;\n+    *) usage_help ;;\n+  esac\n+\n+  set +u                        # need unset array element to evaluate to null\n+  compare_version \"$v\" \"$v_\"\n+  exit 0\n+}\n+\n+function command_diff {\n+  validate_version \"$1\" v1_parts\n+  # shellcheck disable=SC2154\n+  local v1_major=\"${v1_parts[0]}\"\n+  local v1_minor=\"${v1_parts[1]}\"\n+  local v1_patch=\"${v1_parts[2]}\"\n+  local v1_prere=\"${v1_parts[3]}\"\n+  local v1_build=\"${v1_parts[4]}\"\n+\n+  validate_version \"$2\" v2_parts\n+  # shellcheck disable=SC2154\n+  local v2_major=\"${v2_parts[0]}\"\n+  local v2_minor=\"${v2_parts[1]}\"\n+  local v2_patch=\"${v2_parts[2]}\"\n+  local v2_prere=\"${v2_parts[3]}\"\n+  local v2_build=\"${v2_parts[4]}\"\n+\n+  if [ \"${v1_major}\" != \"${v2_major}\" ]; then\n+    echo \"major\"\n+  elif [ \"${v1_minor}\" != \"${v2_minor}\" ]; then\n+    echo \"minor\"\n+  elif [ \"${v1_patch}\" != \"${v2_patch}\" ]; then\n+    echo \"patch\"\n+  elif [ \"${v1_prere}\" != \"${v2_prere}\" ]; then\n+    echo \"prerelease\"\n+  elif [ \"${v1_build}\" != \"${v2_build}\" ]; then\n+    echo \"build\"\n+  fi\n+}\n+\n+# shellcheck disable=SC2034\n+function command_get {\n+    local part version\n+\n+    if [[ \"$#\" -ne \"2\" ]] || [[ -z \"$1\" ]] || [[ -z \"$2\" ]]; then\n+        usage_help\n+        exit 0\n+    fi\n+\n+    part=\"$1\"\n+    version=\"$2\"\n+\n+    validate_version \"$version\" parts\n+    local major=\"${parts[0]}\"\n+    local minor=\"${parts[1]}\"\n+    local patch=\"${parts[2]}\"\n+    local prerel=\"${parts[3]:1}\"\n+    local build=\"${parts[4]:1}\"\n+    local release=\"${major}.${minor}.${patch}\"\n+\n+    case \"$part\" in\n+        major|minor|patch|release|prerel|build) echo \"${!part}\" ;;\n+        *) usage_help ;;\n+    esac\n+\n+    exit 0\n+}\n+\n+function command_validate {\n+  if [[ \"$#\" -ne \"1\" ]]; then\n+        usage_help\n+  fi  \n+  \n+  if [[ \"$1\" =~ $SEMVER_REGEX ]]; then\n+    echo \"valid\"\n+  else\n+    echo \"invalid\"\n+  fi\n+\n+  exit 0\n+}\n+\n+case $# in\n+  0) echo \"Unknown command: $*\"; usage_help;;\n+esac\n+\n+case $1 in\n+  --help|-h) echo -e \"$USAGE\"; exit 0;;\n+  --version|-v) usage_version ;;\n+  bump) shift; command_bump \"$@\";;\n+  get) shift; command_get \"$@\";;\n+  compare) shift; command_compare \"$@\";;\n+  diff) shift; command_diff \"$@\";;\n+  validate) shift; command_validate \"$@\";;\n+  *) echo \"Unknown arguments: $*\"; usage_help;;\n+esac\n","prefixes":["libcamera-devel","2/4"]}