aboutsummaryrefslogtreecommitdiff
path: root/bpkg-util/package-archive.bash.in
blob: ba73a150cb980eb4ee8a71f7485ff3521d03023e (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
# file      : bpkg-util/package-archive.bash.in
# license   : MIT; see accompanying LICENSE file

# Utility functions useful for managing package archives.

if [ "$bpkg_util_package_archive" ]; then
  return 0
else
  bpkg_util_package_archive=true
fi

@import libbutl.bash/manifest-parser@

# We expect the user to set the bpkg_util_bpkg variable to the bpkg program
# path.
#
if [ ! -v bpkg_util_bpkg ]; then
  echo "error: variable bpkg_util_bpkg is not set" >&2
  exit 1
fi

# Extract the package information from a package archive and print it to
# stdout in the '<name>\n<version>\n<project>\n' form, where the project field
# is empty if the project value is not specified in the manifest.
#
# Note that, in particular, it verifies that the archive file name matches the
# package name and version.
#
function bpkg_util_pkg_verify_archive () # <path>
{
  # We can't use the process substitution for input redirect here, since such
  # a process failure is not trapped. Thus, read the manifest file into a
  # variable and parse it afterwards, which is probably ok since package
  # manifests are normally not too big.
  #
  # Note that alternatively we could use the process substitution for running
  # bpkg, treat the name value absence as indication of a failure, and exit
  # with non-zero status if that's the case. Feels a bit hackish though.
  #
  local m
  m="$("$bpkg_util_bpkg" pkg-verify --manifest "$1")"

  butl_manifest_parser_start <<<"$m"

  local name=
  local version=
  local project=

  local n v
  while IFS=: read -ru "$butl_manifest_parser_ofd" -d '' n v; do
    case "$n" in
      name)    name="$v"    ;;
      version) version="$v" ;;
      project) project="$v" ;;
    esac
  done

  butl_manifest_parser_finish

  echo "$name"
  echo "$version"
  echo "$project"
}

# Search for package archives in a directory using the package name and
# version pattern and printing their paths one per line to stdout. If the
# version argument is '*', then print archives for all package versions.
# Otherwise if the version contains the trailing '*', then print archives for
# all revisions of the specified version and for the exact version otherwise.
# For example:
#
# bpkg_util_pkg_find_archives foo '*'    dir/
# bpkg_util_pkg_find_archives foo '1.0*' dir/
# bpkg_util_pkg_find_archives foo '1.0'  dir/
#
# Note that the resulting archive paths include the specified directory as a
# prefix.
#
function bpkg_util_pkg_find_archives () # <name> <version> <dir>
{
  local nam="$1"
  local ver="$2"
  local dir="$3"

  local r=()
  local f

  if [ -d "$dir" ]; then
    local vr # Version with the revision stripped, if search for revisions.
    local np # File name pattern for archives search.

    if [ "$ver" != "*" -a "${ver: -1}" == "*" ]; then  # <version>*
      vr="$(sed -n -re 's%^(\+?[^+]+)(\+[0-9]+)?\*$%\1%p' <<<"$ver")"
      np="$nam-$vr*.*" # foo-1.0*.*, etc.
    else                                               # * or <version>
      np="$nam-$ver.*" # foo-*.*, foo-1.0.*, etc.
    fi

    # Go through the potentially matching archives (for example, for 'foo'
    # '1.2.3+2*': foo-1.2.3.tar.gz, foo-1.2.3+1.tar.gz, foo-1.2.30.tar.gz,
    # etc) and return those which package name and version match properly.
    #
    while read f; do
      local p
      bpkg_util_pkg_verify_archive "$f" | readarray -t p

      local n="${p[0]}"
      local v="${p[1]}"

      if [[ "$n" == "$nam" &&
            ( "$ver" == "*"  || \
              "$v" == "$ver" || \
              ( -n "$vr" && "$v" =~ ^"$vr"(\+[0-9]+)?$ )) ]]; then

        r+=("$f")
      fi
    done < <(find "$dir" -type f -name "$np")
  fi

  for f in "${r[@]}"; do
    echo "$f"
  done
}

# Search for a package archive in a directory using a file name pattern. If
# the archive is found, then print the package information to stdout in the
# '<path>\n<name>\n<version>\n<project>\n' form, where the project field is
# empty if the project value is not specified in the manifest.
#
# Note that if there are multiple archives matching the pattern, then it is
# unspecified which one is picked.
#
function bpkg_util_pkg_find_archive () # <pattern> <dir>
{
  local pat="$1"
  local dir="$2"

  if [ -d "$dir" ]; then
    local f

    # We could probably use -print -quit but this is not portable (NetBSD
    # needs -exit instead of -quit).
    #
    f="$(find "$dir" -type f -name "$pat" | sed -n -e '1p')"

    if [ -n "$f" ]; then

      local p
      bpkg_util_pkg_verify_archive "$f" | readarray -t p

      echo "$f"
      echo "${p[0]}"
      echo "${p[1]}"
      echo "${p[2]}"
      return
    fi
  fi
}