├── .editorconfig ├── .gitattributes ├── .gitignore ├── .gitlab-ci.yml ├── .mailmap ├── APKBUILD.5.scd ├── COPYING ├── Makefile ├── abuild-fetch.c ├── abuild-gzsplit.c ├── abuild-keygen.in ├── abuild-rmtemp.c ├── abuild-sign.in ├── abuild-sudo.c ├── abuild-tar.c ├── abuild.1.scd ├── abuild.conf.5.scd ├── abuild.conf.in ├── abuild.in ├── abump.1.scd ├── abump.in ├── apkbuild-cpan.in ├── apkbuild-gem-resolver.in ├── apkbuild-pypi.in ├── apkgrel.in ├── bootchartd ├── buildlab.in ├── checkapk.in ├── config.guess ├── config.sub ├── default.conf ├── functions.sh.in ├── newapkbuild.1.scd ├── newapkbuild.in ├── sample.APKBUILD ├── sample.confd ├── sample.initd ├── sample.post-install ├── sample.pre-install └── tests ├── abuild_fetch_test ├── abuild_gzsplit_test ├── abuild_keygen_test ├── abuild_sign_test ├── abuild_tar_test ├── abuild_test ├── abump_test ├── apkgrel_test ├── bin └── openssl ├── checkapk_test ├── functions_test ├── test_env.sh ├── testdata ├── .abuild │ ├── abuild.conf │ ├── testkey-62a9ada3.rsa │ └── testkey-62a9ada3.rsa.pub ├── alpine-base-3.11.6-r0.apk ├── alpine-base-3.12.0-r0.apk └── gitconfig └── testrepo ├── dbgpkg ├── APKBUILD └── hello.c ├── invalid-filename └── APKBUILD ├── large-doc-subpkg └── APKBUILD ├── lib64test └── APKBUILD ├── pkg path with spaces ├── APKBUILD └── hello.c ├── pkg1 └── APKBUILD ├── py3 foo and bar └── APKBUILD ├── py3-conflicting-python-versions └── APKBUILD ├── setcap └── APKBUILD ├── subpackage-arch └── APKBUILD ├── test-licenses └── APKBUILD └── test-pkgname └── APKBUILD /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 4 8 | indent_style = tab 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [apkbuild-gem-resolver.in] 13 | indent_size = 2 14 | indent_style = space 15 | 16 | [apkbuild-pypi.in] 17 | indent_size = 4 18 | indent_style = space 19 | 20 | [Makefile] 21 | indent_size = 8 22 | indent_style = tab 23 | 24 | [*.yml] 25 | indent_size = 2 26 | indent_style = space 27 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bats gitlab-language=shell 2 | abuild.in gitlab-language=shell 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.1 2 | *.5 3 | *.o 4 | *.tar.bz2 5 | Kyuafile 6 | abuild 7 | abuild-fetch 8 | abuild-gzsplit 9 | abuild-keygen 10 | abuild-rmtemp 11 | abuild-sign 12 | abuild-sudo 13 | abuild-tar 14 | abuild.conf 15 | abump 16 | ap 17 | apkbuild-cpan 18 | apkbuild-gem-resolver 19 | apkbuild-pypi 20 | apkgrel 21 | buildlab 22 | checkapk 23 | devbuild 24 | functions.sh 25 | newapkbuild 26 | pkg 27 | src 28 | tests/testdata/abuild.key* 29 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - verify 3 | 4 | tests: 5 | image: 6 | name: alpinelinux/abuild-ci 7 | stage: verify 8 | script: 9 | - make 10 | - make check 11 | tags: 12 | - docker-alpine 13 | - x86_64 14 | 15 | build-clang: 16 | image: 17 | name: alpinelinux/abuild-ci 18 | stage: verify 19 | script: [CC=clang make] 20 | tags: 21 | - docker-alpine 22 | - x86_64 23 | 24 | build-scan: 25 | image: 26 | name: alpinelinux/abuild-ci 27 | stage: verify 28 | script: [scan-build --status-bugs make] 29 | tags: 30 | - docker-alpine 31 | - x86_64 32 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Kaarle Ritvanen 2 | -------------------------------------------------------------------------------- /APKBUILD.5.scd: -------------------------------------------------------------------------------- 1 | APKBUILD(5) 2 | 3 | # NAME 4 | 5 | *APKBUILD* - metadata and instructions to build a package 6 | 7 | 8 | # SYNOPSIS 9 | 10 | /usr/src/packages///APKBUILD 11 | 12 | 13 | # DESCRIPTION 14 | 15 | An *APKBUILD* file is used by tools such as abuild(1) to build a package for 16 | eventual installation by the apk(8) package manager. It defines metadata such 17 | as the name of the package, the version information, the source license, 18 | and contact information for the developer. It additionally contains the 19 | commands needed to build, test, and install the package. 20 | 21 | The *APKBUILD* format is similar to a typical shell script; you set 22 | pre-defined variables and implement pre-defined functions, and the abuild(1) 23 | (or similar) utility will use them to create the package. 24 | 25 | 26 | ## Required Variables 27 | 28 | The following variables must be set in all *APKBUILD* files: 29 | 30 | *pkgname* 31 | Specifies the name of the package. This is typically the name of the 32 | package upstream; however, note that all letters must be lowercased. 33 | 34 | Libraries for scripting languages should have a prefix before the 35 | library name describing the language. Such prefixes include _lua-_, 36 | _perl-_, _py-_, and _rb-_. Not all languages use prefixes. For a 37 | definitive list, consult the PREFIXES file in the root directory 38 | of the repository you are using for packaging. 39 | 40 | *pkgver* 41 | Specifies the version of the software being packaged. The version of 42 | a package must consist of one or more numbers separated by the radix 43 | (decimal point). The final number may have a single letter following 44 | it, for upstreams that use such a versioning scheme (such as 1.5a, 45 | 1.5b, 1.5c). 46 | 47 | After the final number (and optional single letter), a suffix may 48 | be appended, which must be an underscore (\_) followed by one of 49 | _alpha_, _beta_, _pre_, _rc_, _cvs_, _svn_, _git_, _hg_, or _p_, 50 | optionally followed by another number. If the suffix is _alpha_, 51 | _beta_, _pre_, or _rc_, it is considered to be earlier than the 52 | version without a suffix; if the suffix is _cvs_, _svn, _git_, _hg_, 53 | or _p_, it is considered to be later than the version without a 54 | suffix. All of the following examples are valid versions, in order 55 | from lowest to highest: 56 | 57 | 1.0, 1.1_alpha2, 1.1.3_pre, 1.1.3, 1.1.3_hg, 1.2, 1.2a, 1.2b 58 | 59 | *pkgrel* 60 | Specifies the package release number of this particular package 61 | version. This indicates when a package has changed without a 62 | corresponding change in version. Always increment *pkgrel* when you 63 | change the contents, dependencies, or metadata of a package. The 64 | first release of a package is always 0. 65 | 66 | *pkgdesc* 67 | Specifies what the package contains. *pkgdesc* must be 128 characters 68 | or less, and should concisely describe what actions the software or 69 | items being package will allow the user to perform. For example, 70 | “Fully-featured word processor with spell check and plugins” 71 | would be a sufficient *pkgdesc* for AbiWord. 72 | 73 | *url* 74 | Specifies the Web address of the package's upstream. This allows users 75 | and future maintainers to find documentation, release information, 76 | and contact information for the package. If no Web address is 77 | available for the package, you must set *url* to an empty string (""). 78 | 79 | *arch* 80 | Specifies the architectures for which the package may be built. It 81 | is highly recommended that you set this variable to "_all_" if the 82 | package is portable. 83 | 84 | You may use "_noarch_" if the package does not contain any 85 | architecture-specific binary files - that is, any files that are 86 | compiled for the target only. Such packages may include pure Python 87 | packages, shell script packages, and JARs. If you are not sure what 88 | this means, using "_all_" is safe. 89 | 90 | Architectures can be negated using the _!_ character to exclude them 91 | from the list of supported architectures. E.g. _arch="all !ppc64le"_ 92 | means that the package is allowed to be built on all architectures 93 | but the ppc64le architecture. 94 | 95 | *license* 96 | Specifies the license under which the package is distributed. The 97 | value provided must match a SPDX license identifier. 98 | 99 | *source* 100 | Specifies the location of both local and remote source files 101 | used to build the package. Typically, the remote source file(s) 102 | or archive(s) is specified, followed by any local patches, install 103 | scripts, configuration files, or other necessary files. 104 | 105 | 106 | ## Optional Variables 107 | 108 | The following variables are not required, but may be set in any *APKBUILD* 109 | file. 110 | 111 | *checkdepends* 112 | Specifies test-time dependencies of the package. Common packages that 113 | are used for testing include check, dejagnu, and perl-test-command. 114 | 115 | *depends* 116 | Specifies the run-time dependencies of the package. The abuild(1) 117 | utility will automatically scan the resultant package for shared 118 | library (.so) dependencies; do not specify them here. 119 | 120 | *install* 121 | Specifies install scripts for the package, if any. See _Install 122 | Scripts_ for more information about install scripts. 123 | 124 | *install_if* 125 | Specifies a condition when apk(8) should automatically install the 126 | package (or subpackage). For instance, the OpenRC subpackages set 127 | 128 | ``` 129 | install_if="openrc ${subpkgname%-openrc}=$pkgver-r$pkgrel" 130 | ``` 131 | 132 | which means that the OpenRC subpackage will be automatically 133 | installed if both OpenRC and the origin package are installed on 134 | the same computer. 135 | 136 | *makedepends* 137 | Specifies build dependencies for the package. 138 | 139 | *maintainer* 140 | The name and email of the package maintainer in RFC 2822 format. 141 | E.g.: _maintainer="Joe Q. Public "_ 142 | 143 | *pkggroups* 144 | Specifies a space-separated list of login groups to create during 145 | build-time. Note that you will need to create the login groups 146 | in a pre-install script as well; see _Install Scripts_ for more 147 | information about install scripts. 148 | 149 | *pkgusers* 150 | Specifies a space-separated list of user logins to create during 151 | build-time. Note that you will need to create the user logins in a 152 | pre-install install script as well; see _Install Scripts_ for more 153 | information about install scripts. 154 | 155 | *provides* 156 | Specifies that the package "provides" the same contents as another 157 | package. There are two formats that you may use for *provides*: 158 | a provider name, and a provider name with version. 159 | 160 | Specifying a provider name with version such as _foobar=1.2_ will 161 | cause the package to be an "alias" of _foobar_ version _1.2_. It 162 | will be automatically installed if a user then runs `apk add foobar` 163 | or similar, and it will conflict with a package named _foobar_. 164 | 165 | Specifying a provider name without a version such as _baz_ will 166 | cause the package to provide a "virtual" called _baz_. Multiple 167 | packages with the same virtual provider can be installed on a system; 168 | however, if a user runs \`apk add baz` they will be provided a list 169 | of packages that provide _baz_ and must select one and install it. 170 | 171 | *provider_priority* 172 | Specifies the numeric value for apk(8) to use for the package when 173 | considering which provider should be installed for the same *provides* 174 | virtual provider. 175 | 176 | *replaces* 177 | Specifies packages that the package replaces. This is typically 178 | used for packages renamed by upstream. 179 | 180 | *replaces_priority* 181 | Specifies the numeric value that is used by apk(8) when multiple 182 | packages with *replaces* include the same file. It is also used 183 | to decide which package should define the permissions of a directory 184 | even without *replaces* set. 185 | 186 | *subpackages* 187 | Specifies subpackages or split packages built with this 188 | package. Typically, this will include _$pkgname-dev_ for development 189 | files (such as _/usr/include_ and static library files) and 190 | _$pkgname-doc_ for documentation (such as _/usr/share/doc_ and 191 | _/usr/share/man_). 192 | 193 | Each subpackage may be specified using three different methods. The 194 | first, and most common, is _$pkgname-foo_ where _foo_ is the name 195 | of the split function specified later in the file. Similar to the 196 | *package* function, the _foo_ function must move files from _$pkgdir_ 197 | or _$srcdir_ to _$subpkgdir_ after creating _$subpkgdir_. 198 | 199 | The second method is to simply call the subpackage _foo_ which will 200 | create a package called _foo_ instead of _$pkgname-foo_. 201 | 202 | However, _foo_ in both of these examples cannot contain an hyphen, 203 | as shell function names cannot have hyphens in them. In this case, 204 | the third method may be used: _foo:funcname_ where _foo_ is the name 205 | of the subpackage and _funcname_ is the name of the shell function 206 | in the *APKBUILD* that creates it. 207 | 208 | *triggers* 209 | Specifies a trigger script used by the package. A trigger script 210 | is a shell script that is called whenever monitored files or 211 | directories are modified. You may specify the paths to monitor 212 | using the triggers variable as follows: 213 | 214 | ``` 215 | $pkgname.trigger=/usr/share/man:/usr/local/share/man 216 | ``` 217 | 218 | This will run the package trigger script whenever files in 219 | _/usr/share/man_ or _/usr/local/share/man_ are created, modified, 220 | or removed. 221 | 222 | *options* 223 | The *options* variable allows you to set parameters for the package 224 | at build time. There are a number of valid options you may set, 225 | and you may set multiple options by writing a space between each one. 226 | Custom option names can be used when they contain exactly one _:_. 227 | Options can be set for a specific (sub)packages by using 228 | _subpkgname::option_ (or _subpkgname:option_ for custom options). 229 | 230 | *!archcheck* 231 | Specifies that the package contains binaries that cannot 232 | run on the target architecture. This is primarily used for 233 | packages containing firmware, and should typically never 234 | be needed. 235 | 236 | *bigdocs* 237 | Specifies that this packages intentionally has a large -doc subpackage. 238 | Thereby suppressing a warning to be emitted if the -doc subpackage 239 | exceeds a certain package size threshold (currently 2 MiB). 240 | 241 | *charset.alias* 242 | Specifies that the package ships a _/usr/lib/charset.alias_ 243 | file and that it should be installed on the user's 244 | system. This is almost never the case. Do not use this option. 245 | 246 | *!check* 247 | Specifies that the package will not run a test suite. The 248 | reason for disabling the check phase should be noted in 249 | a comment. 250 | 251 | *checkroot* 252 | Specifies that this package's test suite will be run in 253 | fakeroot(8). This is necessary for some test suites which 254 | fail when run as non-root. 255 | 256 | *!dbg* 257 | Specifies that the package should not be built with a debug 258 | information package. This is the default unless DEFAULT_DBG 259 | is set in the environment or abuild.conf(5). It is typically 260 | used on packages that do not generate debug information 261 | (such as pure Python packages) or packages that do not 262 | support debug information packages. 263 | 264 | *!fhs* 265 | Specifies that the package violates FHS and installs to a 266 | location such as _/usr/local_, _/opt_, or _/srv_. 267 | 268 | *ldpath-recursive* 269 | Specifies that abuild(1) should use the *--recursive* argument 270 | to scanelf(1) when attempting to find shared library (.so) 271 | dependencies for the package. 272 | 273 | *lib64* 274 | Specifies that the package installs files under _/lib64_ 275 | or _/usr/lib64_ and that the test for those directories 276 | should be skipped. This is discouraged and should only be 277 | used for packages providing compatibility for GNU libc. 278 | 279 | *libtool* 280 | Specifies that the package requires its libtool (.la) 281 | files. They will not be automatically removed by abuild(1). 282 | 283 | *net* 284 | Specifies that the package build system requires access 285 | to a network. This is discouraged and an issue should be 286 | filed with the package's authors. 287 | 288 | *!strip* 289 | Specifies that strip(1) should not be run on any of the 290 | package's binaries. This is automatically implying if the 291 | _-dbg_ subpackage is enabled, or if you are using DEFAULT_DBG. 292 | 293 | *suid* 294 | Specifies that binaries in the package may be installed 295 | set-uid. This is a security risk and it is highly recommended 296 | to use capabilities or process separation instead of set-uid 297 | where available. 298 | 299 | *setcap* 300 | Specifies that binaries in the package may be installed 301 | with extra setcap(8) capabilities. If this option is enabled, 302 | it is highly recommended to only make these binaries executable 303 | by root and users of a specific group, not by others. 304 | 305 | *textrels* 306 | Specifies that the package's binaries are known to contain 307 | relocations against text segments. By default, abuild(1) 308 | will refuse to create such a package because this is a 309 | security concern. 310 | 311 | *toolchain* 312 | Specifies that the package is part of the base toolchain 313 | set and may depend on packages like _g++_. 314 | 315 | *!tracedeps* 316 | Specifies that abuild(1) should not automatically populate 317 | *depends* with shared library (.so) or symlink target 318 | dependencies. 319 | 320 | 321 | ## Automatic Variables 322 | 323 | The following variables are defined for you by abuild(1), but may be 324 | overridden if necessary. 325 | 326 | *builddir* 327 | Specifies the directory where the source code of the package will 328 | be built. The default value is _$srcdir/$pkgname-$pkgver_ which 329 | is appropriate for most source distributions. If the source tarball 330 | does not create a _$pkgname-$pkgver_ directory when it is unpacked, 331 | you must override *builddir*. 332 | 333 | *pkgdir* 334 | Specifies the directory where the built files will be 335 | installed. Typically, you will call `make DESTDIR="$pkgdir" install` 336 | or similar to install the files. The default value is _$startdir/pkg_ 337 | and you should not modify this variable. 338 | 339 | *srcdir* 340 | Specifies the directory where the files specified in *source* 341 | are downloaded and unpacked. The default value is _$startdir/src_ 342 | and you should not need to modify this. 343 | 344 | *startdir* 345 | Specifies the directory where the *APKBUILD* file resides. 346 | 347 | *subpkgdir* 348 | Specifies the directory where the subpackage's files should be 349 | placed. This variable is only set inside subpackage functions. 350 | 351 | 352 | ## Special Variables 353 | 354 | The following variables are used only in special circumstances, and may 355 | be required or optional depending on their usage and the contents of other 356 | variables. 357 | 358 | *depends_dev* 359 | Specifies the run-time dependencies of the _-dev_ subpackage. 360 | 361 | *depends_doc* 362 | Specifies the run-time dependencies of the _-doc_ subpackage. 363 | 364 | *depends_libs* 365 | Specifies the run-time dependencies of the _-libs_ subpackage. 366 | 367 | *depends_openrc* 368 | Specifies the run-time dependencies of the _-openrc_ subpackage. 369 | 370 | *depends_static* 371 | Specifies the run-time dependencies of the _-static_ subpackage. 372 | 373 | *giturl* 374 | Specifies the URL of the Git repository to use with `abuild 375 | snapshot`. If the default branch of the repository is not desired, 376 | a different one may be specified by appending *-b* _branch_ where 377 | _branch_ is the branch to checkout. 378 | 379 | 380 | ## Functions 381 | 382 | Functions specified here may be present in any *APKBUILD* file, but with 383 | the exception of *package*, are not strictly required. 384 | 385 | *fetch* 386 | This function is called to download the remote files in *source*. 387 | 388 | *unpack* 389 | This function unpacks any archives in *source* to *srcdir*. 390 | 391 | *prepare* 392 | Prepares the source in *srcdir* to be built. The default *prepare* 393 | function ensures the build directories are set up correctly and 394 | applies any _\*.patch_ files specified in *source*. You must call 395 | *default_prepare* if you write a custom *prepare* function. 396 | 397 | *build* 398 | Compiles the source in *builddir*. You must implement this function 399 | yourself. If no compilation is required, you may omit it. 400 | 401 | *check* 402 | Runs the package's test suite. This function must implemented unless 403 | *!check* was specified in *options*. 404 | 405 | *package* 406 | Installs the package into *pkgdir*. Note that *pkgdir* is not 407 | created for you; if this package installs no files (for example, 408 | a metapackage), you must use `mkdir -p "$pkgdir"` to skip the 409 | package phase. 410 | 411 | 412 | ## Install Scripts 413 | 414 | An install script is run when an action is taken on a package by apk(8). An 415 | install script must be written in shell and must have a _#!/bin/sh_ 416 | interpreter declaration as the first line. The *install* variable must 417 | contain the install scripts needed by the package. 418 | 419 | The install script will be run inside the root filesystem where the package 420 | is being installed. A single argument will be passed to call scripts, which 421 | is the version of the package being currently installed (or deinstalled). The 422 | pre-upgrade and post-upgrade scripts will have an additional second argument, 423 | which specifies the version of the package before the upgrade process. 424 | 425 | The different actions that may have install scripts specified are as follows: 426 | 427 | *$pkgname.pre-install* 428 | Executed before the package is installed. If this script exits with 429 | an error (non-zero exit code), apk(8) will halt the installation and 430 | the package will not be installed. This install script is typically 431 | used to create any users or groups needed as described in *pkggroups* 432 | and *pkgusers*. 433 | 434 | *$pkgname.post-install* 435 | Executed after the package is installed. If this script exits 436 | with an error (non-zero exit code), apk(8) will mark the package as 437 | broken. The `apk fix` command will attempt to re-run the post-install 438 | script if this occurs. 439 | 440 | *$pkgname.pre-upgrade* 441 | Executed before the package is upgraded. If this script exits with 442 | an error (non-zero exit code), apk(8) will mark the package as broken. 443 | 444 | *$pkgname.post-upgrade* 445 | Executed after the package is upgraded. If this script exits with 446 | an error (non-zero exit code), apk(8) will mark the package as 447 | broken. The `apk fix` command will attempt to re-run the post-upgrade 448 | script if this occurs. 449 | 450 | *$pkgname.pre-deinstall* 451 | Executed before the package is removed from the system. If this 452 | script exits with an error (non-zero exit code), apk(8) will not 453 | remove the package from the system. 454 | 455 | *$pkgname.post-deinstall* 456 | Executed after the package is removed from the system. Exiting with 457 | an error will have no effect. 458 | 459 | 460 | # IMPLEMENTATION NOTES 461 | 462 | Currently, *APKBUILD* files are sourced as normal shells scripts. This may 463 | change at a later date. 464 | 465 | 466 | # COMPATIBILITY 467 | 468 | The abuild(1) utility as distributed by Alpine Linux uses the BusyBox 469 | Almquist shell, a part of busybox(1) that is currently undocumented. It is 470 | mostly compliant with IEEE Std 1003.2 (“POSIX.2”), with some bash-like 471 | extensions. The abuild(1) utility as distributed by Adélie uses the user's 472 | preferred /bin/sh, which is typically bash(1). 473 | 474 | 475 | # SEE ALSO 476 | 477 | SPDX license reference (on the Web at ), 478 | abuild(1), newapkbuild(1), apk(8), buildrepo(1). 479 | 480 | 481 | # HISTORY 482 | 483 | The *APKBUILD* format and abuild(1) utility first appeared in Alpine 484 | Linux 1.9. 485 | 486 | 487 | # AUTHORS 488 | 489 | Timo Teräs <_timo.teras@iki.fi_>++ 490 | Natanael Copa <_ncopa@alpinelinux.org_> 491 | 492 | Documentation:++ 493 | A. Wilcox <_awilfox@adelielinux.org_> 494 | 495 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | GNU GENERAL PUBLIC LICENSE 3 | 4 | Version 2, June 1991 5 | 6 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 7 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 8 | 9 | Everyone is permitted to copy and distribute verbatim copies 10 | of this license document, but changing it is not allowed. 11 | Preamble 12 | 13 | The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation`s software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 14 | 15 | When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. 16 | 17 | To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. 18 | 19 | For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. 20 | 21 | We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. 22 | 23 | Also, for each author`s protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors` reputations. 24 | 25 | Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone`s free use or not licensed at all. 26 | 27 | The precise terms and conditions for copying, distribution and modification follow. 28 | 29 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 30 | 31 | 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". 32 | 33 | Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 34 | 35 | 1. You may copy and distribute verbatim copies of the Program`s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. 36 | 37 | You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 38 | 39 | 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: 40 | 41 | a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. 42 | b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. 43 | c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) 44 | These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. 45 | 46 | Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. 47 | 48 | In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 49 | 50 | 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: 51 | 52 | a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, 53 | b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, 54 | c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) 55 | The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. 56 | 57 | If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 58 | 59 | 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 60 | 61 | 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 62 | 63 | 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients` exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 64 | 65 | 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. 66 | 67 | If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. 68 | 69 | It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. 70 | 71 | This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 72 | 73 | 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 74 | 75 | 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 76 | 77 | Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 78 | 79 | 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. 80 | 81 | NO WARRANTY 82 | 83 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 84 | 85 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 86 | 87 | END OF TERMS AND CONDITIONS 88 | 89 | How to Apply These Terms to Your New Programs 90 | 91 | If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. 92 | 93 | To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. 94 | 95 | one line to give the program`s name and an idea of what it does. 96 | Copyright (C) yyyy name of author 97 | 98 | This program is free software; you can redistribute it and/or 99 | modify it under the terms of the GNU General Public License 100 | as published by the Free Software Foundation; either version 2 101 | of the License, or (at your option) any later version. 102 | 103 | This program is distributed in the hope that it will be useful, 104 | but WITHOUT ANY WARRANTY; without even the implied warranty of 105 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 106 | GNU General Public License for more details. 107 | 108 | You should have received a copy of the GNU General Public License 109 | along with this program; if not, write to the Free Software 110 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 111 | Also add information on how to contact you by electronic and paper mail. 112 | 113 | If the program is interactive, make it output a short notice like this when it starts in an interactive mode: 114 | 115 | Gnomovision version 69, Copyright (C) year name of author 116 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details 117 | type `show w`. This is free software, and you are welcome 118 | to redistribute it under certain conditions; type `show c` 119 | for details. 120 | The hypothetical commands `show w` and `show c` should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w` and `show c`; they could even be mouse-clicks or menu items--whatever suits your program. 121 | 122 | You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: 123 | 124 | Yoyodyne, Inc., hereby disclaims all copyright 125 | interest in the program `Gnomovision` 126 | (which makes passes at compilers) written 127 | by James Hacker. 128 | 129 | signature of Ty Coon, 1 April 1989 130 | Ty Coon, President of Vice 131 | This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. 132 | 133 | 134 | In addition, as a special exception, the copyright holder 135 | gives permission to link the code of this program with 136 | any version of the OpenSSL library which is distributed 137 | under a license identical to that listed in the included 138 | COPYING.OpenSSL file, and distribute linked combinations 139 | including the two. You must obey the GNU General Public 140 | License in all respects for all of the code used other 141 | than OpenSSL. If you modify this file, you may extend this 142 | exception to your version of the file, but you are not 143 | obligated to do so. If you do not wish to do so, delete 144 | this exception statement from your version. 145 | 146 | 147 | This program is free software; you can redistribute it and/or modify 148 | it under the terms of the GNU General Public License as published by 149 | the Free Software Foundation, version 2 of the License 150 | 151 | This program is distributed in the hope that it will be useful, 152 | but WITHOUT ANY WARRANTY; without even the implied warranty of 153 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154 | GNU General Public License for more details. 155 | 156 | You should have received a copy of the GNU General Public License 157 | along with this program; if not, write to the Free Software 158 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 159 | 160 | 161 | LICENSE ISSUES 162 | ============== 163 | 164 | The OpenSSL toolkit stays under a dual license, i.e. both the conditions of 165 | the OpenSSL License and the original SSLeay license apply to the toolkit. 166 | See below for the actual license texts. Actually both licenses are BSD-style 167 | Open Source licenses. In case of any license issues related to OpenSSL 168 | please contact openssl-core@openssl.org. 169 | 170 | OpenSSL License 171 | --------------- 172 | 173 | /* ==================================================================== 174 | * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. 175 | * 176 | * Redistribution and use in source and binary forms, with or without 177 | * modification, are permitted provided that the following conditions 178 | * are met: 179 | * 180 | * 1. Redistributions of source code must retain the above copyright 181 | * notice, this list of conditions and the following disclaimer. 182 | * 183 | * 2. Redistributions in binary form must reproduce the above copyright 184 | * notice, this list of conditions and the following disclaimer in 185 | * the documentation and/or other materials provided with the 186 | * distribution. 187 | * 188 | * 3. All advertising materials mentioning features or use of this 189 | * software must display the following acknowledgment: 190 | * "This product includes software developed by the OpenSSL Project 191 | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 192 | * 193 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 194 | * endorse or promote products derived from this software without 195 | * prior written permission. For written permission, please contact 196 | * openssl-core@openssl.org. 197 | * 198 | * 5. Products derived from this software may not be called "OpenSSL" 199 | * nor may "OpenSSL" appear in their names without prior written 200 | * permission of the OpenSSL Project. 201 | * 202 | * 6. Redistributions of any form whatsoever must retain the following 203 | * acknowledgment: 204 | * "This product includes software developed by the OpenSSL Project 205 | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 206 | * 207 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 208 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 209 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 210 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 211 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 213 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 214 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 215 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 216 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 217 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 218 | * OF THE POSSIBILITY OF SUCH DAMAGE. 219 | * ==================================================================== 220 | * 221 | * This product includes cryptographic software written by Eric Young 222 | * (eay@cryptsoft.com). This product includes software written by Tim 223 | * Hudson (tjh@cryptsoft.com). 224 | * 225 | */ 226 | 227 | Original SSLeay License 228 | ----------------------- 229 | 230 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 231 | * All rights reserved. 232 | * 233 | * This package is an SSL implementation written 234 | * by Eric Young (eay@cryptsoft.com). 235 | * The implementation was written so as to conform with Netscapes SSL. 236 | * 237 | * This library is free for commercial and non-commercial use as long as 238 | * the following conditions are aheared to. The following conditions 239 | * apply to all code found in this distribution, be it the RC4, RSA, 240 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation 241 | * included with this distribution is covered by the same copyright terms 242 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). 243 | * 244 | * Copyright remains Eric Young's, and as such any Copyright notices in 245 | * the code are not to be removed. 246 | * If this package is used in a product, Eric Young should be given attribution 247 | * as the author of the parts of the library used. 248 | * This can be in the form of a textual message at program startup or 249 | * in documentation (online or textual) provided with the package. 250 | * 251 | * Redistribution and use in source and binary forms, with or without 252 | * modification, are permitted provided that the following conditions 253 | * are met: 254 | * 1. Redistributions of source code must retain the copyright 255 | * notice, this list of conditions and the following disclaimer. 256 | * 2. Redistributions in binary form must reproduce the above copyright 257 | * notice, this list of conditions and the following disclaimer in the 258 | * documentation and/or other materials provided with the distribution. 259 | * 3. All advertising materials mentioning features or use of this software 260 | * must display the following acknowledgement: 261 | * "This product includes cryptographic software written by 262 | * Eric Young (eay@cryptsoft.com)" 263 | * The word 'cryptographic' can be left out if the rouines from the library 264 | * being used are not cryptographic related :-). 265 | * 4. If you include any Windows specific code (or a derivative thereof) from 266 | * the apps directory (application code) you must include an acknowledgement: 267 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 268 | * 269 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 270 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 272 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 273 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 274 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 275 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 276 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 277 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 278 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 279 | * SUCH DAMAGE. 280 | * 281 | * The licence and distribution terms for any publically available version or 282 | * derivative of this code cannot be changed. i.e. this code cannot simply be 283 | * copied and put under another distribution licence 284 | * [including the GNU Public Licence.] 285 | */ 286 | 287 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE := abuild 2 | VERSION := 3.15.0 3 | 4 | prefix ?= /usr 5 | bindir ?= $(prefix)/bin 6 | sysconfdir ?= /etc 7 | sharedir ?= $(prefix)/share/$(PACKAGE) 8 | mandir ?= $(prefix)/share/man 9 | 10 | SCRIPTS := abuild abuild-keygen abuild-sign newapkbuild \ 11 | abump apkgrel buildlab apkbuild-cpan apkbuild-pypi checkapk \ 12 | apkbuild-gem-resolver 13 | USR_BIN_FILES := $(SCRIPTS) abuild-tar abuild-gzsplit abuild-sudo abuild-fetch abuild-rmtemp 14 | MAN_1_PAGES := newapkbuild.1 abuild.1 abump.1 15 | MAN_5_PAGES := APKBUILD.5 abuild.conf.5 16 | SAMPLES := sample.APKBUILD sample.initd sample.confd \ 17 | sample.pre-install sample.post-install 18 | MAN_PAGES := $(MAN_1_PAGES) $(MAN_5_PAGES) 19 | AUTOTOOLS_TOOLCHAIN_FILES := config.sub config.guess 20 | 21 | SCRIPT_SOURCES := $(addsuffix .in,$(SCRIPTS)) 22 | 23 | GIT_REV := $(shell test -d .git && git describe || echo exported) 24 | ifneq ($(GIT_REV), exported) 25 | FULL_VERSION := $(patsubst $(PACKAGE)-%,%,$(GIT_REV)) 26 | FULL_VERSION := $(patsubst v%,%,$(FULL_VERSION)) 27 | else 28 | FULL_VERSION := $(VERSION) 29 | endif 30 | 31 | CHMOD := chmod 32 | SED := sed 33 | TAR := tar 34 | SCDOC := scdoc 35 | LINK = $(CC) $(OBJS-$@) -o $@ $(LDFLAGS) $(LDFLAGS-$@) $(LIBS-$@) 36 | 37 | CFLAGS ?= -Wall -Werror -g -pedantic 38 | 39 | SED_REPLACE := -e 's:@VERSION@:$(FULL_VERSION):g' \ 40 | -e 's:@prefix@:$(prefix):g' \ 41 | -e 's:@sysconfdir@:$(sysconfdir):g' \ 42 | -e 's:@sharedir@:$(sharedir):g' \ 43 | 44 | SSL_CFLAGS ?= $(shell pkg-config --cflags openssl) 45 | SSL_LDFLAGS ?= $(shell pkg-config --cflags openssl) 46 | SSL_LIBS ?= $(shell pkg-config --libs openssl) 47 | ZLIB_LIBS ?= $(shell pkg-config --libs zlib) 48 | 49 | OBJS-abuild-tar = abuild-tar.o 50 | CFLAGS-abuild-tar.o = $(SSL_CFLAGS) 51 | LDFLAGS-abuild-tar = $(SSL_LDFLAGS) 52 | LIBS-abuild-tar = $(SSL_LIBS) 53 | LIBS-abuild-tar.static = $(LIBS-abuild-tar) 54 | 55 | OBJS-abuild-gzsplit = abuild-gzsplit.o 56 | LDFLAGS-abuild-gzsplit = $(ZLIB_LIBS) 57 | 58 | OBJS-abuild-sudo = abuild-sudo.o 59 | OBJS-abuild-fetch = abuild-fetch.o 60 | 61 | TEST_TIMEOUT = 60 62 | 63 | .SUFFIXES: .conf.in .sh.in .in 64 | %.conf: %.conf.in 65 | ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ 66 | 67 | %.sh: %.sh.in 68 | ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ 69 | ${CHMOD} +x $@ 70 | 71 | %: %.in 72 | ${SED} ${SED_REPLACE} ${SED_EXTRA} $< > $@ 73 | ${CHMOD} +x $@ 74 | 75 | %.1: %.1.scd 76 | ${SCDOC} < $< > $@ 77 | 78 | %.5: %.5.scd 79 | ${SCDOC} < $< > $@ 80 | 81 | P=$(PACKAGE)-$(VERSION) 82 | 83 | all: $(USR_BIN_FILES) $(MAN_PAGES) functions.sh abuild.conf 84 | 85 | clean: 86 | @rm -f $(USR_BIN_FILES) $(MAN_PAGES) *.o functions.sh abuild.conf Kyuafile \ 87 | tests/Kyuafile tests/testdata/abuild.key* 88 | 89 | %.o: %.c 90 | $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS-$@) -o $@ -c $< 91 | 92 | abuild-sudo: abuild-sudo.o 93 | $(LINK) 94 | 95 | abuild-tar: abuild-tar.o 96 | $(LINK) 97 | 98 | abuild-fetch: abuild-fetch.o 99 | $(LINK) 100 | 101 | abuild-gzsplit: abuild-gzsplit.o 102 | $(LINK) 103 | 104 | abuild-tar.static: abuild-tar.o 105 | $(CC) -static $(CPPFLAGS) $(CFLAGS) $(CFLAGS-$@) $^ -o $@ $(LIBS-$@) 106 | 107 | help: 108 | @echo "$(P) makefile" 109 | @echo "usage: make install [ DESTDIR= ]" 110 | 111 | tests/testdata/abuild.key: 112 | openssl genrsa -out "$@" 4096 113 | 114 | tests/testdata/abuild.key.pub: tests/testdata/abuild.key 115 | openssl rsa -in "$<" -pubout -out "$@" 116 | 117 | tests/Kyuafile: $(wildcard tests/*_test) 118 | echo "syntax(2)" > $@ 119 | echo "test_suite('abuild')" >> $@ 120 | for i in $(notdir $(wildcard tests/*_test)); do \ 121 | echo "atf_test_program{name='$$i',timeout=$(TEST_TIMEOUT)}" >> $@ ; \ 122 | done 123 | 124 | Kyuafile: tests/Kyuafile 125 | echo "syntax(2)" > $@ 126 | echo "test_suite('abuild')" >> $@ 127 | echo "include('tests/Kyuafile')" >> $@ 128 | 129 | check: $(SCRIPTS) $(USR_BIN_FILES) functions.sh tests/Kyuafile Kyuafile tests/testdata/abuild.key.pub 130 | kyua --variable parallelism=$(shell nproc) test || (kyua report --verbose && exit 1) 131 | 132 | install: $(USR_BIN_FILES) $(SAMPLES) $(MAN_PAGES) $(AUTOTOOLS_TOOLCHAIN_FILES) default.conf abuild.conf functions.sh 133 | install -D -m 755 -t $(DESTDIR)/$(bindir)/ $(USR_BIN_FILES);\ 134 | chmod 4555 $(DESTDIR)/$(bindir)/abuild-sudo 135 | for i in adduser addgroup apk; do \ 136 | ln -fs abuild-sudo $(DESTDIR)/$(bindir)/abuild-$$i; \ 137 | done 138 | install -D -m 644 -t $(DESTDIR)/$(mandir)/man1/ $(MAN_1_PAGES);\ 139 | install -D -m 644 -t $(DESTDIR)/$(mandir)/man5/ $(MAN_5_PAGES);\ 140 | if [ -n "$(DESTDIR)" ] || [ ! -f "/$(sysconfdir)"/abuild.conf ]; then\ 141 | install -D -m 644 -t $(DESTDIR)/$(sysconfdir)/ abuild.conf; \ 142 | fi 143 | 144 | install -D -t $(DESTDIR)/$(sharedir)/ $(AUTOTOOLS_TOOLCHAIN_FILES) 145 | install -D -m 644 -t $(DESTDIR)/$(sharedir)/ functions.sh default.conf $(SAMPLES) 146 | 147 | depends depend: 148 | sudo apk --no-cache -U --virtual .abuild-depends add openssl-dev openssl-libs-static zlib-dev 149 | 150 | .gitignore: Makefile 151 | echo "*.tar.bz2" > $@ 152 | for i in $(USR_BIN_FILES); do\ 153 | echo $$i >>$@;\ 154 | done 155 | 156 | 157 | .PHONY: install 158 | -------------------------------------------------------------------------------- /abuild-fetch.c: -------------------------------------------------------------------------------- 1 | /* MIT license 2 | 3 | Copyright (C) 2015 Natanael Copa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | */ 24 | 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | static char *program; 41 | static char lockfile[PATH_MAX] = ""; 42 | 43 | struct cmdarray { 44 | size_t argc; 45 | char *argv[32]; 46 | }; 47 | 48 | void add_opt(struct cmdarray *cmd, char *opt) 49 | { 50 | cmd->argv[cmd->argc++] = opt; 51 | cmd->argv[cmd->argc] = NULL; 52 | } 53 | 54 | int usage(int eval) 55 | { 56 | printf("usage: %s [-hk] [-d DESTDIR] URL\n", program); 57 | return eval; 58 | } 59 | 60 | int fork_exec(char *argv[], int showerr) 61 | { 62 | int r = 202; 63 | int status = 0; 64 | pid_t childpid = fork(); 65 | if (childpid < 0 ) 66 | err(200, "fork"); 67 | 68 | if (childpid == 0) { 69 | execvp(argv[0], argv); 70 | if (showerr) 71 | warn("%s", argv[0]); 72 | _exit(201); 73 | } 74 | 75 | /* wait for curl/wget and get the exit code */ 76 | wait(&status); 77 | if (WIFEXITED(status)) 78 | r = WEXITSTATUS(status); 79 | return r; 80 | } 81 | 82 | static int acquire_lock(const char *lockfile) 83 | { 84 | int lockfd, i, r; 85 | 86 | /* try to work around an ESTALE error which occurs on NFS */ 87 | for (i = 0; i < 10; i++, sleep(1)) { 88 | lockfd = open(lockfile, O_WRONLY|O_CREAT, 0660); 89 | if (lockfd < 0) 90 | err(1, "%s", lockfile); 91 | 92 | r = lockf(lockfd, F_LOCK, 0); 93 | if (r == 0 || errno != ESTALE) 94 | break; 95 | 96 | close(lockfd); 97 | } 98 | 99 | if (r != 0) 100 | err(1, "failed to acquire lock: %s", lockfile); 101 | 102 | return lockfd; 103 | } 104 | 105 | static void release_lock(int lockfd) 106 | { 107 | if (lockf(lockfd, F_ULOCK, 0) == -1) 108 | err(1, "failed to release lock"); 109 | 110 | } 111 | 112 | static int try_lock(int lockfd) 113 | { 114 | return lockf(lockfd, F_TLOCK, 0) == 0; 115 | } 116 | 117 | /* create or wait for an NFS-safe lockfile and fetch url with curl or wget */ 118 | int fetch(char *url, const char *destdir, bool insecure) 119 | { 120 | int lockfd, status=0; 121 | char outfile[PATH_MAX-5], partfile[PATH_MAX]; 122 | char *name, *p; 123 | struct cmdarray curlcmd = { 124 | .argc = 5, 125 | .argv = { "curl", "-L", "-f", "-o", partfile, NULL } 126 | }; 127 | struct cmdarray wgetcmd = { 128 | .argc = 3, 129 | .argv = { "wget", "-O", partfile, NULL } 130 | }; 131 | 132 | name = strrchr(url, '/'); 133 | if (name == NULL) 134 | errx(1, "%s: no '/' in url", url); 135 | p = strstr(url, "::"); 136 | if (p != NULL) { 137 | name = url; 138 | *p = '\0'; 139 | url = p + 2; 140 | } else { 141 | name++; 142 | } 143 | 144 | snprintf(outfile, sizeof(outfile), "%s/%s", destdir, name); 145 | snprintf(lockfile, sizeof(lockfile), "%s.lock", outfile); 146 | snprintf(partfile, sizeof(partfile), "%s.part", outfile); 147 | 148 | lockfd = acquire_lock(lockfile); 149 | 150 | if (access(outfile, F_OK) == 0) 151 | goto fetch_done; 152 | 153 | /* enable insecure mode when http. This may be useful when it redirects to https */ 154 | if (insecure || strstr(url, "http://") == url) { 155 | add_opt(&curlcmd, "--insecure"); 156 | add_opt(&wgetcmd, "--no-check-certificate"); 157 | } 158 | 159 | if (access(partfile, F_OK) == 0) { 160 | printf("Partial download found. Trying to resume.\n"); 161 | add_opt(&curlcmd, "--continue-at"); 162 | add_opt(&curlcmd, "-"); 163 | add_opt(&wgetcmd, "-c"); 164 | } 165 | 166 | add_opt(&curlcmd, url); 167 | add_opt(&wgetcmd, url); 168 | 169 | status = fork_exec(curlcmd.argv, 0); 170 | 171 | /* CURLE_RANGE_ERROR (33) 172 | The server does not support or accept range requests. */ 173 | if (status == 33) { 174 | unlink(partfile); 175 | if( curlcmd.argc >=3) { 176 | /* remove --continue-at - options */ 177 | curlcmd.argv[curlcmd.argc-3] = curlcmd.argv[curlcmd.argc-1]; 178 | curlcmd.argv[curlcmd.argc-2] = NULL; 179 | curlcmd.argc -= 2; 180 | status = fork_exec(curlcmd.argv, 0); 181 | } 182 | } 183 | 184 | /* is we failed execute curl, then fallback to wget */ 185 | if (status == 201) 186 | status = fork_exec(wgetcmd.argv, 1); 187 | 188 | /* only rename completed downloads */ 189 | if (status == 0) 190 | rename(partfile, outfile); 191 | 192 | fetch_done: 193 | release_lock(lockfd); 194 | 195 | // give other processes the chance to acquire the lock if they have the file open 196 | // sleep for a millisecond 197 | const struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000}; 198 | nanosleep(&ts, NULL); 199 | 200 | if (status == 0 || try_lock(lockfd)) 201 | unlink(lockfile); 202 | close(lockfd); 203 | return status; 204 | } 205 | 206 | void sighandler(int sig) 207 | { 208 | switch(sig) { 209 | case SIGABRT: 210 | case SIGINT: 211 | case SIGQUIT: 212 | case SIGTERM: 213 | unlink(lockfile); 214 | exit(0); 215 | break; 216 | default: 217 | break; 218 | } 219 | } 220 | 221 | /* exit codes get passed through from curl/wget (so we can check in abuild 222 | whether the server does not support resuming). Additional exit codes: 223 | 200: fork failed 224 | 201: curl/wget could not be started 225 | 202: curl/wget did not terminate normally 226 | 203: usage displayed */ 227 | int main(int argc, char *argv[]) 228 | { 229 | int opt; 230 | bool insecure = false; 231 | char *destdir = "/var/cache/distfiles"; 232 | 233 | program = argv[0]; 234 | while ((opt = getopt(argc, argv, "hd:k")) != -1) { 235 | switch (opt) { 236 | case 'h': 237 | return usage(0); 238 | break; 239 | case 'd': 240 | destdir = optarg; 241 | break; 242 | case 'k': 243 | insecure = true; 244 | break; 245 | default: 246 | printf("Unknown option '%c'\n", opt); 247 | return usage(1); 248 | break; 249 | } 250 | } 251 | 252 | argv += optind; 253 | argc -= optind; 254 | 255 | if (argc != 1) 256 | return usage(203); 257 | 258 | signal(SIGABRT, sighandler); 259 | signal(SIGINT, sighandler); 260 | signal(SIGQUIT, sighandler); 261 | signal(SIGTERM, sighandler); 262 | 263 | return fetch(argv[0], destdir, insecure); 264 | } 265 | -------------------------------------------------------------------------------- /abuild-gzsplit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | static int find_section(const char *buf, size_t bufsize, const char *str) { 10 | int len = strlen(str); 11 | const char *p; 12 | 13 | if (len >= bufsize) return 0; 14 | 15 | p = strrchr(buf, '/'); 16 | if (p++ == NULL) p = buf; 17 | return strncmp(p, str, len) == 0; 18 | } 19 | 20 | int main(void) 21 | { 22 | char obuf[8*1024], ibuf[8*1024]; 23 | z_stream zs; 24 | int r = Z_OK, rc = 1, fd = -1; 25 | size_t len; 26 | 27 | if (inflateInit2(&zs, 15+32) != Z_OK) 28 | goto err; 29 | 30 | zs.avail_out = sizeof obuf; 31 | zs.next_out = (Bytef *)obuf; 32 | 33 | while (1) { 34 | const char *fn = NULL; 35 | 36 | if (zs.avail_in == 0) { 37 | zs.avail_in = read(STDIN_FILENO, ibuf, sizeof ibuf); 38 | zs.next_in = (Bytef *)ibuf; 39 | if (zs.avail_in < 0) { 40 | warn("Failed to read input"); 41 | goto err; 42 | } 43 | if (zs.avail_in == 0 && r == Z_STREAM_END) goto ok; 44 | } 45 | 46 | r = inflate(&zs, Z_NO_FLUSH); 47 | if (r != Z_OK && r != Z_STREAM_END) { 48 | warnx("Failed to inflate input"); 49 | goto err; 50 | } 51 | 52 | len = sizeof obuf - zs.avail_out; 53 | if (len) { 54 | if (fd < 0) { 55 | const char *fn; 56 | 57 | if (find_section(obuf, len, ".SIGN.")) 58 | fn = "signatures.tar.gz"; 59 | else if (find_section(obuf, len, ".PKGINFO")) 60 | fn = "control.tar.gz"; 61 | else if (rc == 1) 62 | fn = "data.tar.gz", rc = 2; 63 | else { 64 | warnx("Failed to find .PKGINFO section"); 65 | goto err; 66 | } 67 | fd = open(fn, O_CREAT|O_TRUNC|O_WRONLY, 0777); 68 | if (fd < 0) { 69 | warn("Failed to open %s", fn); 70 | goto err; 71 | } 72 | } 73 | zs.next_out = (Bytef *)obuf; 74 | zs.avail_out = sizeof obuf; 75 | } 76 | 77 | if (zs.avail_in == 0 || r == Z_STREAM_END) { 78 | len = (char *)zs.next_in - (char *)ibuf; 79 | if (write(fd, ibuf, len) != len) { 80 | warn("Failed to write to %s", fn); 81 | goto err; 82 | } 83 | memmove(ibuf, zs.next_in, zs.avail_in); 84 | zs.next_in = (Bytef *)ibuf; 85 | } 86 | 87 | if (r == Z_STREAM_END) { 88 | if (fd >= 0) { 89 | close(fd); 90 | fd = -1; 91 | } 92 | inflateEnd(&zs); 93 | if (inflateInit2(&zs, 15+32) != Z_OK) { 94 | warnx("inflateInit2 failed"); 95 | goto err; 96 | } 97 | } 98 | } 99 | ok: 100 | rc = 0; 101 | err: 102 | if (fd >= 0) close(fd); 103 | inflateEnd(&zs); 104 | return rc; 105 | } 106 | 107 | -------------------------------------------------------------------------------- /abuild-keygen.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # abuild-keygen - generate signing keys 4 | # Copyright (c) 2009 Natanael Copa 5 | # 6 | # Distributed under GPL-2.0-only 7 | # 8 | 9 | program_version=@VERSION@ 10 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 11 | SUDO="${SUDO-$(command -v doas || command -v sudo || echo doas)}" 12 | 13 | if ! [ -f "$sharedir/functions.sh" ]; then 14 | echo "$sharedir/functions.sh: not found" >&2 15 | exit 1 16 | fi 17 | . "$sharedir/functions.sh" 18 | 19 | set -e 20 | 21 | # ask for privkey unless non-interactive mode 22 | # returns value in global $privkey 23 | get_privkey_file() { 24 | local emailaddr default_name 25 | emailaddr=${PACKAGER##*<} 26 | emailaddr=${emailaddr%%>*} 27 | 28 | # if PACKAGER does not contain a valid email address, then ask git 29 | if [ -z "$emailaddr" ] || [ "${emailaddr##*@}" = "$emailaddr" ]; then 30 | emailaddr=$(${GIT:-git} config --get user.email 2>/dev/null || true) 31 | fi 32 | 33 | default_name="${emailaddr:-$USER}-$(printf "%x" $(date +%s))" 34 | 35 | privkey="$ABUILD_USERDIR/$default_name.rsa" 36 | if [ -z "$interactive" ]; then 37 | return 0 38 | fi 39 | msg "Generating public/private rsa key pair for abuild" 40 | echo -n "Enter file in which to save the key [$privkey]: " 41 | 42 | read line 43 | if [ -n "$line" ]; then 44 | privkey="$line" 45 | fi 46 | } 47 | 48 | do_keygen() { 49 | mkdir -p "$ABUILD_USERDIR" 50 | 51 | get_privkey_file 52 | pubkey="$privkey.pub" 53 | 54 | # generate the private key in a subshell with stricter umask 55 | ( 56 | umask 0007 57 | openssl genrsa -out "$privkey" "$numbits" 58 | ) 59 | openssl rsa -in "$privkey" -pubout -out "$pubkey" 60 | 61 | if [ -n "$install_pubkey" ]; then 62 | msg "Installing $pubkey to /etc/apk/keys..." 63 | $SUDO mkdir -p "${abuild_keygen_install_root}"/etc/apk/keys 64 | $SUDO cp ${interactive:+-i} "$pubkey" "${abuild_keygen_install_root}"/etc/apk/keys/ 65 | else 66 | 67 | msg "" 68 | msg "You'll need to install $pubkey into " 69 | msg "/etc/apk/keys to be able to install packages and repositories signed with" 70 | msg "$privkey" 71 | fi 72 | 73 | if [ -n "$append_config" ]; then 74 | if [ -f "$ABUILD_USERCONF" ]; then 75 | # comment out the existing values 76 | sed -i -e 's/^PACKAGER_PRIVKEY=/\#&/' "$ABUILD_USERCONF" 77 | fi 78 | echo "PACKAGER_PRIVKEY=\"$privkey\"" >> "$ABUILD_USERCONF" 79 | else 80 | msg "" 81 | msg "You might want add following line to $ABUILD_USERCONF:" 82 | msg "" 83 | msg "PACKAGER_PRIVKEY=\"$privkey\"" 84 | msg "" 85 | fi 86 | 87 | msg "" 88 | msg "Please remember to make a safe backup of your private key:" 89 | msg "$privkey" 90 | msg "" 91 | } 92 | 93 | do_kernel_key() { 94 | mkdir -p "$ABUILD_USERDIR" 95 | pem="$ABUILD_USERDIR"/kernel_signing_key.pem 96 | ( 97 | umask 0007 98 | # https://www.kernel.org/doc/html/v6.1/admin-guide/module-signing.html#generating-signing-keys 99 | openssl req -verbose -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \ 100 | -outform PEM -out "$pem" \ 101 | -keyout "$pem" -config - <<-EOF 102 | [ req ] 103 | default_bits = 4096 104 | distinguished_name = req_distinguished_name 105 | prompt = no 106 | string_mask = utf8only 107 | x509_extensions = myexts 108 | 109 | [ req_distinguished_name ] 110 | O = alpinelinux.org 111 | CN = Alpine Linux kernel key 112 | #emailAddress = unspecified.user@unspecified.company 113 | 114 | [ myexts ] 115 | basicConstraints=critical,CA:FALSE 116 | keyUsage=digitalSignature 117 | subjectKeyIdentifier=hash 118 | authorityKeyIdentifier=keyid 119 | EOF 120 | ) 121 | msg "Kernel signing key was created: $pem" 122 | if ! grep -q "^KERNEL_SIGNING_KEY=" "$ABUILD_USERCONF" 2>/dev/null; then 123 | echo "KERNEL_SIGNING_KEY='$pem'" >> "$ABUILD_USERCONF" 124 | fi 125 | msg "KERNEL_SIGNING_KEY='$pem' was added to $ABUILD_USERCONF" 126 | } 127 | 128 | usage() { 129 | cat <<-__EOF__ 130 | $program $program_version - generate signing keys 131 | Usage: $program [-a|--append] [-i|--install] [-n] 132 | Options: 133 | -a, --append Set PACKAGER_PRIVKEY= in 134 | $ABUILD_USERCONF 135 | 136 | -i, --install Install public key into /etc/apk/keys using doas 137 | -n Non-interactive. Use defaults 138 | --kernel Generate a key for kernel modules 139 | -b, --numbits [BITS] The size of the private key to generate in bits. 140 | -q, --quiet 141 | -h, --help Show this help 142 | 143 | The SUDO variable can be set to pick which tool can be used to 144 | elevate privileges, if it is not set it defaults to doas or sudo if doas 145 | is not found. 146 | 147 | __EOF__ 148 | } 149 | 150 | append_config= 151 | install_pubkey= 152 | interactive=1 153 | numbits=4096 154 | quiet= 155 | kernel_key= 156 | 157 | args=$(getopt -o ab:inqh --long append,numbits:,install,quiet,help,kernel -n "$program" -- "$@") 158 | if [ $? -ne 0 ]; then 159 | usage 160 | exit 2 161 | fi 162 | eval set -- "$args" 163 | while true; do 164 | case $1 in 165 | -a|--append) append_config=1;; 166 | -i|--install) install_pubkey=1;; 167 | --kernel) kernel_key=1;; 168 | -n) unset interactive ;; 169 | -b|--numbits) numbits="$2"; shift 1;; 170 | -q|--quiet) quiet=1;; # suppresses msg 171 | -h|--help) usage; exit;; 172 | --) shift; break;; 173 | *) usage >&2; exit 1;; # getopt error 174 | esac 175 | shift 176 | done 177 | if [ $# -ne 0 ]; then 178 | usage >&2 179 | exit 2 180 | fi 181 | 182 | if [ -n "$kernel_key" ]; then 183 | do_kernel_key 184 | exit 185 | fi 186 | do_keygen 187 | -------------------------------------------------------------------------------- /abuild-rmtemp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * abuild-rmtemp 3 | * Copyright (c) 2017 Kaarle Ritvanen 4 | * Distributed under GPL-2.0-only 5 | */ 6 | 7 | #define _XOPEN_SOURCE 700 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define PREFIX "/var/tmp/abuild." 20 | 21 | static void fail(void) { 22 | errx(1, "%s", strerror(errno)); 23 | } 24 | 25 | static int handler(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { 26 | return remove(fpath); 27 | } 28 | 29 | int main(int argc, char **argv) { 30 | if (argc < 2) return 0; 31 | 32 | if (getuid()) { 33 | argv[0] = "-abuild-rmtemp"; 34 | execv("/usr/bin/abuild-sudo", argv); 35 | } 36 | 37 | if (strncmp(argv[1], PREFIX, strlen(PREFIX)) || \ 38 | strchr(argv[1] + strlen(PREFIX), '/')) 39 | errx(1, "Invalid path: %s", argv[1]); 40 | 41 | struct stat s; 42 | if (lstat(argv[1], &s)) fail(); 43 | struct passwd *p = getpwnam(getenv("USER")); 44 | if (!p) errx(1, "Incorrect user"); 45 | if (s.st_uid != p->pw_uid) errx(1, "Permission denied"); 46 | 47 | if (nftw(argv[1], handler, 512, FTW_DEPTH|FTW_PHYS)) fail(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /abuild-sign.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # abuild-sign - sign indexes 4 | # Copyright (c) 2009 Natanael Copa 5 | # 6 | # Distributed under GPL-2.0-only 7 | # 8 | 9 | program_version=@VERSION@ 10 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 11 | 12 | if ! [ -f "$sharedir/functions.sh" ]; then 13 | echo "$sharedir/functions.sh: not found" >&2 14 | exit 1 15 | fi 16 | . "$sharedir/functions.sh" 17 | 18 | gzip=$(command -v pigz || echo gzip) 19 | 20 | do_sign() { 21 | local f i keyname repo openssl 22 | openssl=$(command -v openssl || echo libressl) 23 | 24 | # we are actually only interested in the name, not the file itself 25 | keyname=${pubkey##*/} 26 | 27 | for f; do 28 | i=$(readlink -f $f) 29 | [ -d "$i" ] && i="$i/APKINDEX.tar.gz" 30 | repo="${i%/*}" 31 | trap 'die "failed to sign $i"' EXIT 32 | set -e 33 | cd "$repo" 34 | sig=".SIGN.$sigtype.$keyname" 35 | $openssl dgst $dgstargs -sign "$privkey" -out "$sig" "$i" 36 | 37 | if [ -n "$SOURCE_DATE_EPOCH" ]; then 38 | touch -h -d "@$SOURCE_DATE_EPOCH" "$sig" 39 | fi 40 | 41 | tmptargz=$(mktemp) 42 | apk_tar --owner=0 --group=0 --numeric-owner "$sig" | abuild-tar --cut | $gzip -n -9 > "$tmptargz" 43 | tmpsigned=$(mktemp) 44 | cat "$tmptargz" "$i" > "$tmpsigned" 45 | rm -f "$tmptargz" "$sig" 46 | chmod 644 "$tmpsigned" 47 | mv "$tmpsigned" "$i" 48 | msg "Signed $i" 49 | set +e 50 | trap - EXIT 51 | done 52 | } 53 | 54 | usage() { 55 | cat <<-__EOF__ 56 | $program $program_version - sign indexes 57 | Usage: $program [-k PRIVKEY] [-p PUBKEY] INDEXFILE... 58 | $program -e 59 | Options: 60 | -e, --installed Check only of there exist a private key for signing 61 | -k, --private KEY The private key to use for signing 62 | -p, --public KEY The name of public key. apk add will look for 63 | /etc/apk/keys/KEY 64 | -t, --type TYPE The signature type RSA or RSA256 65 | -q, --quiet 66 | -h, --help Show this help 67 | 68 | __EOF__ 69 | } 70 | 71 | check_installed=false 72 | privkey="$PACKAGER_PRIVKEY" 73 | pubkey= 74 | quiet= 75 | 76 | args=$(getopt -o ek:p:t:qh --long installed,private:,public:,type:,quiet,help -n "$program" -- "$@") 77 | if [ $? -ne 0 ]; then 78 | usage >&2 79 | exit 2 80 | fi 81 | eval set -- "$args" 82 | while true; do 83 | case $1 in 84 | -e|--installed) check_installed=true;; 85 | -k|--private) privkey=$2; shift;; 86 | -p|--public) pubkey=$2; shift;; 87 | -t|--type) sigtype=$2; shift;; 88 | -q|--quiet) quiet=1;; # suppresses msg 89 | -h|--help) usage; exit;; 90 | --) shift; break;; 91 | *) exit 1;; # getopt error 92 | esac 93 | shift 94 | done 95 | if [ $# -eq 0 ] && ! $check_installed; then 96 | usage >&2 97 | exit 2 98 | fi 99 | 100 | if [ -z "$privkey" ]; then 101 | cat >&2 <<-__EOF__ 102 | No private key found. Use 'abuild-keygen' to generate the keys. 103 | Then you can either: 104 | * set the PACKAGER_PRIVKEY in $ABUILD_USERCONF 105 | ('abuild-keygen -a' does this for you) 106 | * set the PACKAGER_PRIVKEY in $ABUILD_CONF 107 | * specify the key with the -k option to $program 108 | 109 | __EOF__ 110 | exit 1 111 | fi 112 | 113 | if [ -z "$pubkey" ]; then 114 | pubkey=${PACKAGER_PUBKEY:-"${privkey}.pub"} 115 | fi 116 | 117 | if [ -z "$sigtype" ]; then 118 | sigtype=RSA 119 | fi 120 | 121 | case $sigtype in 122 | RSA) dgstargs="-sha1";; 123 | RSA256) dgstargs="-sha256";; 124 | *) 125 | echo "$program: supported types are RSA and RSA256" >&2 126 | exit 1 127 | ;; 128 | esac 129 | if $check_installed; then 130 | if ! [ -e "$privkey" ]; then 131 | echo "$program: $privkey: File not found" >&2 132 | exit 1 133 | fi 134 | if ! [ -e "$pubkey" ]; then 135 | echo "$program: $pubkey: File not found" >&2 136 | exit 1 137 | fi 138 | else 139 | do_sign "$@" 140 | fi 141 | -------------------------------------------------------------------------------- /abuild-sudo.c: -------------------------------------------------------------------------------- 1 | /* abuild-sudo.c - limited root privileges for users in "abuild" group 2 | * 3 | * Copyright (C) 2012 Natanael Copa 4 | * All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 as published 8 | * by the Free Software Foundation. See http://www.gnu.org/ for details. 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #ifndef ABUILD_GROUP 22 | #define ABUILD_GROUP "abuild" 23 | #endif 24 | 25 | static const char* valid_cmds[] = { 26 | "/bin/adduser", 27 | "/usr/sbin/adduser", 28 | "/bin/addgroup", 29 | "/usr/sbin/addgroup", 30 | "/sbin/apk", 31 | "/usr/bin/abuild-rmtemp", 32 | NULL 33 | }; 34 | 35 | static const char* invalid_opts[] = { 36 | "--allow-untrusted", 37 | "--keys-dir", 38 | NULL, 39 | }; 40 | 41 | const char *get_command_path(const char *cmd) 42 | { 43 | const char *p; 44 | int i; 45 | for (i = 0; valid_cmds[i] != NULL; i++) { 46 | if (access(valid_cmds[i], F_OK) == -1) 47 | continue; 48 | p = strrchr(valid_cmds[i], '/') + 1; 49 | if (strcmp(p, cmd) == 0) 50 | return valid_cmds[i]; 51 | } 52 | return NULL; 53 | } 54 | 55 | void check_option(const char *opt) 56 | { 57 | int i; 58 | for (i = 0; invalid_opts[i] != NULL; i++) 59 | if (strcmp(opt, invalid_opts[i]) == 0) 60 | errx(1, "%s: not allowed option", opt); 61 | } 62 | 63 | int is_in_group(gid_t group) 64 | { 65 | int ngroups_max = getgroups(0, 0); 66 | gid_t *buf = malloc(ngroups_max * sizeof(gid_t)); 67 | int ngroups; 68 | int i; 69 | if (buf == NULL) { 70 | perror("malloc"); 71 | return 0; 72 | } 73 | ngroups = getgroups(ngroups_max, buf); 74 | for (i = 0; i < ngroups; i++) { 75 | if (buf[i] == group) 76 | break; 77 | } 78 | free(buf); 79 | return i < ngroups; 80 | } 81 | 82 | int main(int argc, const char *argv[]) 83 | { 84 | struct group *grent; 85 | const char *cmd; 86 | const char *path; 87 | int i; 88 | struct passwd *pw; 89 | 90 | grent = getgrnam(ABUILD_GROUP); 91 | if (grent == NULL) 92 | errx(1, "%s: Group not found", ABUILD_GROUP); 93 | 94 | char *name = NULL; 95 | uid_t uid = getuid(); 96 | pw = getpwuid(uid); 97 | if (pw) 98 | name = pw->pw_name; 99 | 100 | if (uid != 0 && !is_in_group(grent->gr_gid)) { 101 | errx(1, "User %s is not a member of group %s\n", 102 | name ? name : "(unknown)", ABUILD_GROUP); 103 | } 104 | 105 | if (name == NULL) 106 | warnx("Could not find username for uid %d\n", uid); 107 | setenv("USER", name ? name : "", 1); 108 | 109 | cmd = strrchr(argv[0], '/'); 110 | if (cmd) 111 | cmd++; 112 | else 113 | cmd = argv[0]; 114 | cmd = strchr(cmd, '-'); 115 | if (cmd == NULL) 116 | errx(1, "Calling command has no '-'"); 117 | cmd++; 118 | 119 | path = get_command_path(cmd); 120 | if (path == NULL) 121 | errx(1, "%s: Not a valid subcommand", cmd); 122 | 123 | for (i = 1; i < argc; i++) 124 | check_option(argv[i]); 125 | 126 | argv[0] = path; 127 | /* set our uid to root so bbsuid --install works */ 128 | if (setuid(0) < 0) 129 | err(1, "setuid(0) failed"); 130 | /* set our gid to root so apk commit hooks run with the same gid as for "sudo apk add ..." */ 131 | if (setgid(0) < 0) 132 | err(1, "setgid(0) failed"); 133 | execv(path, (char * const*)argv); 134 | perror(path); 135 | return 1; 136 | } 137 | -------------------------------------------------------------------------------- /abuild-tar.c: -------------------------------------------------------------------------------- 1 | /* abuild-tar.c - A TAR mangling utility for .APK packages 2 | * 3 | * Copyright (C) 2009-2014 Timo Teräs 4 | * All rights reserved. 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License version 2 as published 8 | * by the Free Software Foundation. See http://www.gnu.org/ for details. 9 | */ 10 | 11 | #define _GNU_SOURCE 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | #ifndef VERSION 24 | #define VERSION "" 25 | #endif 26 | 27 | struct tar_header { 28 | /* ustar header, Posix 1003.1 */ 29 | char name[100]; /* 0-99 */ 30 | char mode[8]; /* 100-107 */ 31 | char uid[8]; /* 108-115 */ 32 | char gid[8]; /* 116-123 */ 33 | char size[12]; /* 124-135 */ 34 | char mtime[12]; /* 136-147 */ 35 | char chksum[8]; /* 148-155 */ 36 | char typeflag; /* 156-156 */ 37 | char linkname[100]; /* 157-256 */ 38 | char magic[8]; /* 257-264 */ 39 | char uname[32]; /* 265-296 */ 40 | char gname[32]; /* 297-328 */ 41 | char devmajor[8]; /* 329-336 */ 42 | char devminor[8]; /* 337-344 */ 43 | char prefix[155]; /* 345-499 */ 44 | char padding[12]; /* 500-511 */ 45 | }; 46 | 47 | #define GET_OCTAL(s) get_octal(s, sizeof(s)) 48 | #define PUT_OCTAL(s,v) put_octal(s, sizeof(s), v) 49 | 50 | static inline int dx(int c) 51 | { 52 | if (c >= '0' && c <= '9') 53 | return c - '0'; 54 | if (c >= 'a' && c <= 'f') 55 | return c - 'a' + 0xa; 56 | if (c >= 'A' && c <= 'F') 57 | return c - 'A' + 0xa; 58 | return -1; 59 | } 60 | 61 | static size_t get_octal(char *s, size_t l) 62 | { 63 | size_t val; 64 | int ch; 65 | 66 | val = 0; 67 | while (l && s[0] != 0) { 68 | ch = dx(s[0]); 69 | if (ch < 0 || ch >= 8) 70 | break; 71 | val *= 8; 72 | val += ch; 73 | 74 | s++; 75 | l--; 76 | } 77 | 78 | return val; 79 | } 80 | 81 | static void put_octal(char *s, size_t l, size_t value) 82 | { 83 | char *ptr = &s[l - 1]; 84 | 85 | *(ptr--) = '\0'; 86 | while (value != 0 && ptr >= s) { 87 | *(ptr--) = '0' + (value % 8); 88 | value /= 8; 89 | } 90 | while (ptr >= s) 91 | *(ptr--) = '0'; 92 | } 93 | 94 | static void tarhdr_checksum(struct tar_header *hdr) 95 | { 96 | const unsigned char *src; 97 | size_t chksum, i; 98 | 99 | /* Recalculate checksum */ 100 | memset(hdr->chksum, ' ', sizeof(hdr->chksum)); 101 | src = (const unsigned char *) hdr; 102 | for (i = chksum = 0; i < sizeof(*hdr); i++) 103 | chksum += src[i]; 104 | put_octal(hdr->chksum, sizeof(hdr->chksum)-1, chksum); 105 | } 106 | 107 | static int usage(FILE *out) 108 | { 109 | fprintf(out, 110 | "abuild-tar " VERSION "\n" 111 | "\n" 112 | "usage: abuild-tar [--hash[=]] [--cut]\n" 113 | "\n" 114 | "options:\n" 115 | " --hash[=sha1|md5] Read tar archive from stdin, precalculate hash for \n" 116 | " regular entries and output tar archive on stdout\n" 117 | " --cut Remove the end of file tar record\n" 118 | "\n"); 119 | return 1; 120 | } 121 | 122 | static ssize_t full_read(int fd, void *buf, size_t count) 123 | { 124 | ssize_t total, n; 125 | char *p = buf; 126 | 127 | total = 0; 128 | do { 129 | n = read(fd, p, count); 130 | if (n < 0 && errno == EINTR) 131 | continue; 132 | if (n <= 0) 133 | break; 134 | p += n; 135 | total += n; 136 | count -= n; 137 | } while (1); 138 | 139 | if (total == 0 && n < 0) 140 | return -errno; 141 | 142 | return total; 143 | } 144 | 145 | static ssize_t full_write(int fd, const void *buf, size_t count) 146 | { 147 | ssize_t total, n; 148 | const char *p = buf; 149 | 150 | total = 0; 151 | do { 152 | n = write(fd, p, count); 153 | if (n < 0 && errno == EINTR) 154 | continue; 155 | if (n <= 0) 156 | break; 157 | p += n; 158 | total += n; 159 | count -= n; 160 | } while (1); 161 | 162 | if (total == 0 && n < 0) 163 | return -errno; 164 | 165 | return total; 166 | } 167 | 168 | #if defined(__linux__) 169 | static ssize_t full_splice(int from_fd, int to_fd, size_t count) 170 | { 171 | ssize_t total, n; 172 | 173 | total = 0; 174 | do { 175 | n = splice(from_fd, NULL, to_fd, NULL, count, 0); 176 | if (n < 0 && errno == EINTR) 177 | continue; 178 | if (n <= 0) 179 | break; 180 | count -= n; 181 | total += n; 182 | } while (1); 183 | 184 | if (total == 0 && n < 0) 185 | return -errno; 186 | 187 | return total; 188 | } 189 | #else 190 | #define full_splice(from_fd, to_fd, count) -1 191 | #endif 192 | 193 | #define BUF_INITIALIZER {0} 194 | struct buf { 195 | char *ptr; 196 | size_t size; 197 | size_t alloc; 198 | }; 199 | 200 | static void buf_free(struct buf *b) 201 | { 202 | free(b->ptr); 203 | } 204 | 205 | static int buf_resize(struct buf *b, size_t newsize) 206 | { 207 | void *ptr; 208 | 209 | if (b->alloc >= newsize) return 0; 210 | ptr = realloc(b->ptr, newsize); 211 | if (!ptr) return -ENOMEM; 212 | b->ptr = ptr; 213 | b->alloc = newsize; 214 | return 0; 215 | } 216 | 217 | static int buf_padto(struct buf *b, size_t alignment) 218 | { 219 | size_t oldsize, newsize; 220 | oldsize = b->size; 221 | newsize = (oldsize + alignment - 1) & -alignment; 222 | if (buf_resize(b, newsize)) return -ENOMEM; 223 | b->size = newsize; 224 | if (b->ptr) 225 | memset(b->ptr + oldsize, 0, newsize - oldsize); 226 | return 0; 227 | } 228 | 229 | static int buf_read_fd(struct buf *b, int fd, size_t size) 230 | { 231 | ssize_t r; 232 | 233 | r = buf_resize(b, size); 234 | if (r) return r; 235 | 236 | r = full_read(fd, b->ptr, size); 237 | if (r == size) { 238 | b->size = r; 239 | return 0; 240 | } 241 | b->size = 0; 242 | if (r < 0) return r; 243 | return -EIO; 244 | } 245 | 246 | static int buf_write_fd(struct buf *b, int fd) 247 | { 248 | ssize_t r; 249 | r = full_write(fd, b->ptr, b->size); 250 | if (r == b->size) return 0; 251 | if (r < 0) return r; 252 | return -ENOSPC; 253 | } 254 | 255 | static int buf_add_ext_header_hexdump(struct buf *b, const char *hdr, const unsigned char *value, int valuelen) 256 | { 257 | int i, len; 258 | 259 | /* "%u %s=%s\n" */ 260 | len = 1 + 1 + strlen(hdr) + 1 + valuelen*2 + 1; 261 | for (i = len; i > 9; i /= 10) len++; 262 | 263 | if (buf_resize(b, b->size + len)) return -ENOMEM; 264 | if (b->ptr == NULL) 265 | return 0; 266 | b->size += snprintf(&b->ptr[b->size], len, "%u %s=", len, hdr); 267 | for (i = 0; i < valuelen; i++) 268 | b->size += snprintf(&b->ptr[b->size], 3, "%02x", (int)value[i]); 269 | b->ptr[b->size++] = '\n'; 270 | 271 | return 0; 272 | } 273 | 274 | static int do_it(const EVP_MD *md, int cut) 275 | { 276 | char checksumhdr[32]; 277 | unsigned char digest[EVP_MAX_MD_SIZE]; 278 | struct buf data = BUF_INITIALIZER, pax = BUF_INITIALIZER; 279 | struct tar_header hdr, paxhdr; 280 | size_t name_len, size, aligned_size; 281 | int dohash = 0, r, ret = 1; 282 | 283 | memset(&paxhdr, 0, sizeof(paxhdr)); 284 | 285 | if (md) snprintf(checksumhdr, sizeof(checksumhdr), "APK-TOOLS.checksum.%s", EVP_MD_name(md)); 286 | 287 | do { 288 | if (full_read(STDIN_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr)) 289 | goto err; 290 | 291 | if (cut && hdr.name[0] == 0) 292 | break; 293 | 294 | size = GET_OCTAL(hdr.size); 295 | aligned_size = (size + 511) & ~511; 296 | 297 | if (hdr.typeflag == 'x') { 298 | memcpy(&paxhdr, &hdr, sizeof(hdr)); 299 | if (buf_read_fd(&pax, STDIN_FILENO, aligned_size)) goto err; 300 | pax.size = size; 301 | continue; 302 | } 303 | 304 | dohash = md && (hdr.typeflag == '0' || hdr.typeflag == '7' || hdr.typeflag == '2'); 305 | if (dohash) { 306 | if (buf_read_fd(&data, STDIN_FILENO, aligned_size)) goto err; 307 | 308 | if (hdr.typeflag != '2') { 309 | EVP_Digest(data.ptr, size, digest, NULL, md, NULL); 310 | } else { 311 | name_len = strnlen(hdr.linkname, sizeof(hdr.linkname)); 312 | EVP_Digest(hdr.linkname, name_len, digest, NULL, md, NULL); 313 | } 314 | 315 | buf_add_ext_header_hexdump(&pax, checksumhdr, digest, EVP_MD_size(md)); 316 | PUT_OCTAL(paxhdr.size, pax.size); 317 | tarhdr_checksum(&paxhdr); 318 | } 319 | 320 | if (pax.size) { 321 | /* write pax header + content */ 322 | if (full_write(STDOUT_FILENO, &paxhdr, sizeof(paxhdr)) != sizeof(paxhdr) || 323 | buf_padto(&pax, 512) || 324 | buf_write_fd(&pax, STDOUT_FILENO)) goto err; 325 | } 326 | 327 | if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr)) goto err; 328 | 329 | if (dohash) { 330 | if (buf_write_fd(&data, STDOUT_FILENO)) goto err; 331 | } else if (aligned_size != 0) { 332 | r = full_splice(STDIN_FILENO, STDOUT_FILENO, aligned_size); 333 | if (r == -1) { 334 | while (aligned_size > 0) { 335 | if (full_read(STDIN_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr)) 336 | goto err; 337 | if (full_write(STDOUT_FILENO, &hdr, sizeof(hdr)) != sizeof(hdr)) 338 | goto err; 339 | aligned_size -= sizeof(hdr); 340 | } 341 | } else if (r != aligned_size) goto err; 342 | } 343 | 344 | memset(&paxhdr, 0, sizeof(paxhdr)); 345 | pax.size = 0; 346 | } while (1); 347 | 348 | ret = 0; 349 | err: 350 | buf_free(&data); 351 | buf_free(&pax); 352 | return ret; 353 | } 354 | 355 | int main(int argc, char **argv) 356 | { 357 | static int cut = 0, help = 0; 358 | static const struct option options[] = { 359 | { "hash", optional_argument }, 360 | { "help", no_argument, &help, 1 }, 361 | { "cut", no_argument, &cut, 1 }, 362 | { NULL } 363 | }; 364 | const EVP_MD *md = NULL; 365 | char *digest = NULL; 366 | int ndx; 367 | 368 | OpenSSL_add_all_algorithms(); 369 | #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR < 3 370 | ENGINE_load_builtin_engines(); 371 | ENGINE_register_all_complete(); 372 | #endif 373 | 374 | int c; 375 | while ((c = getopt_long(argc, argv, "", options, &ndx)) != -1) { 376 | if (c == '?') 377 | return usage(stderr); 378 | if (ndx == 0) 379 | digest = optarg ? optarg : "sha1"; 380 | } 381 | 382 | if (help) 383 | return usage(stdout) && 0; 384 | 385 | if (digest == NULL && cut == 0) 386 | return usage(stderr); 387 | if (isatty(STDIN_FILENO)) 388 | return usage(stderr); 389 | 390 | if (digest != NULL) { 391 | md = EVP_get_digestbyname(digest); 392 | if (md == NULL) 393 | return usage(stderr); 394 | } 395 | 396 | return do_it(md, cut); 397 | } 398 | -------------------------------------------------------------------------------- /abuild.1.scd: -------------------------------------------------------------------------------- 1 | abuild(1) 2 | 3 | # NAME 4 | 5 | *abuild* - build an apk from an APKBUILD 6 | 7 | # SYNOPSIS 8 | 9 | *abuild* [options] [-C DIR] [-P _REPODEST_] [-s _SRCDEST_] [-D _DESCRIPTION_] [cmd] ... 10 | 11 | # DESCRIPTION 12 | 13 | *abuild* builds an apk binary package based on an input APKBUILD(5), as well as 14 | other related operations. 15 | 16 | # OPTIONS 17 | 18 | *-A* 19 | Print CARCH and exit 20 | 21 | *-c* 22 | Enable colored output 23 | 24 | *-C DIR* 25 | Change directory to DIR before running any commands 26 | 27 | *-d* 28 | Disable dependency checking 29 | 30 | *-D DESCRIPTION* 31 | Set APKINDEX description (default: *$repo $(git describe)*) 32 | 33 | *-f* 34 | Force specified cmd (skip checks: apk up to date, arch) 35 | 36 | *-F* 37 | Force run as root 38 | 39 | *-h* 40 | Show this help 41 | 42 | *-k* 43 | Keep built packages, even if APKBUILD or sources are newer 44 | 45 | *-K* 46 | Keep buildtime temp dirs and files (srcdir/pkgdir/deps) 47 | 48 | *-m* 49 | Disable colors (monochrome) 50 | 51 | *-P REPODEST* 52 | Set REPODEST as the repository location for created packages 53 | 54 | *-q* 55 | Quiet 56 | 57 | *-r* 58 | Install missing dependencies from system repository 59 | 60 | *-s SRCDEST* 61 | Set source package destination directory to SRCDEST 62 | 63 | *-v* 64 | Verbose: show every command as it is run (very noisy) 65 | 66 | # COMMANDS 67 | 68 | *all* 69 | Runs the entire build process. This is the default when no other command is 70 | specified, and is roughly an alias for *validate builddeps clean fetch 71 | unpack prepare mkusers build check rootpkg*. 72 | 73 | *build* 74 | Compile and install package into *$pkgdir*. 75 | 76 | *check* 77 | Run any defined tests concerning the package 78 | 79 | *checksum* 80 | Generate checksum to be included in APKBUILD 81 | 82 | *clean* 83 | Remove temp build and install dirs 84 | 85 | *cleancache* 86 | Remove downloaded files from $SRCDEST 87 | 88 | *cleanoldpkg* 89 | Remove binary packages except current version 90 | 91 | *cleanpkg* 92 | Remove already built binary and source package 93 | 94 | *deps* 95 | Install packages listed in makedepends and depends 96 | 97 | *fetch* 98 | Fetch sources to $SRCDEST (consider: 'abuild fetch verify') 99 | 100 | *index* 101 | Regenerate indexes in $REPODEST 102 | 103 | *listpkg* 104 | List target packages 105 | 106 | *package* 107 | Install project into 108 | 109 | *prepare* 110 | Apply patches 111 | 112 | *rootbld* 113 | Build package in clean chroot. Requires *abuild-rootbld*. 114 | 115 | *rootpkg* 116 | Run 'package', the split functions and create apks as fakeroot 117 | 118 | *validate* 119 | Basic validation of APKBUILD 120 | 121 | *snapshot* 122 | Create a *$giturl* snapshot and upload to *$disturl* 123 | 124 | *sourcecheck* 125 | Check if remote source package exists upstream 126 | 127 | *srcpkg* 128 | Make a source package 129 | 130 | *undeps* 131 | Uninstall packages listed in makedepends and depends 132 | 133 | *unpack* 134 | Unpack sources to $srcdir 135 | 136 | *up2date* 137 | Compare target and sources dates 138 | 139 | *verify* 140 | Verify checksums 141 | 142 | # ENVIRONMENT 143 | 144 | *APKBUILD* 145 | Override path to *APKBUILD* file. 146 | 147 | *BOOTSTRAP* 148 | Used when bootstrapping with no existing packages by minimising build 149 | dependencies. This flag only has an effect on a few select packages. 150 | 151 | A value of _nocc_ omits any compilation (e.g.: include only source headers). 152 | A value of _nolibc_ assumes that no _libc_ is available. 153 | 154 | This list of values is not exhaustive. 155 | 156 | *CHOST* 157 | Generate packages for given arch or hostspec. 158 | 159 | *CTARGET* 160 | Generate compiler for given arch or hostspec. 161 | 162 | *MOVE_CACHES* 163 | Don't use global cache directories for Go and Cargo. 164 | 165 | *PACKAGER* 166 | Name and email of the packages in RFC5322 format. 167 | E.g.: *John Doe *. 168 | 169 | *PACKAGER_PRIVKEY* 170 | Path to a private key used to sign packages. 171 | 172 | *REPODEST* 173 | Packages shall be stored in _$REPODEST/$repo/$arch/$pkgname-$pkgver-r$pkgrel.apk_, 174 | where *$repo* is the base name of the parent directory of *$startdir*. 175 | 176 | *SOURCE_DATE_EPOCH* 177 | Use this timestamp as a reference for reproducible builds. 178 | See *https://reproducible-builds.org/docs/source-date-epoch/* 179 | 180 | *SUDO_APK* 181 | Command to use to run apk as root. Defaults to *abuild-apk*. 182 | 183 | *USE_CCACHE* 184 | If set to a non-empty value, enables *ccache* support. 185 | 186 | *USE_COLORS* 187 | If set to a non-empty value, print coloured output using ANSI escape 188 | sequences. 189 | 190 | # FILES 191 | 192 | /etc/abuild.conf 193 | Configuration is read from this file by default. 194 | 195 | $HOME/.abuild/abuild.conf 196 | User-specific configuration is read from this file, if it exists. 197 | 198 | # EXAMPLES 199 | 200 | Update checksums for an APKBUILD: 201 | 202 | ``` 203 | abuild checksum 204 | ``` 205 | 206 | Build an APKBUILD and print coloured output: 207 | 208 | ``` 209 | abuild -rc 210 | ``` 211 | 212 | # SEE ALSO 213 | 214 | SPDX license reference (on the Web at ), 215 | newapkbuild(1), apk(8), APKBUILD(5), abuild.conf(5), buildrepo(1). 216 | 217 | # AUTHORS 218 | 219 | *abuild*: Natanael Copa <_ncopa@alpinelinux.org_> 220 | 221 | Documentation:++ 222 | Hugo Osvaldo Barrera <_hugo@whynothugo.nl_> 223 | -------------------------------------------------------------------------------- /abuild.conf.5.scd: -------------------------------------------------------------------------------- 1 | abuild.conf(5) 2 | 3 | # NAME 4 | 5 | *abuild.conf* - configuration file for abuild 6 | 7 | # DESCRIPTION 8 | 9 | *abuild.conf* is the configuration for the *abuild(1)* program. 10 | 11 | # FORMAT 12 | 13 | The configuration file is parsed as a shell script; variables are defined as 14 | regular shell variables. 15 | 16 | For a list of supported variables, see the ENVIRONMENT section of the 17 | *abuild(1)* manual page. 18 | 19 | # EXAMPLE 20 | 21 | ``` 22 | PACKAGER_PRIVKEY="/home/jane/.abuild/jane@example.com-87ac18ca.rsa" 23 | PACKAGER="Jane Doe " 24 | USE_COLORS=1 25 | ``` 26 | 27 | # SEE ALSO 28 | 29 | abuild(1) 30 | -------------------------------------------------------------------------------- /abuild.conf.in: -------------------------------------------------------------------------------- 1 | # defaults are in @sharedir@/default.conf 2 | # 3 | # uncomment line below to enable colors 4 | #USE_COLORS=1 5 | 6 | # uncomment line below to enable ccache support. 7 | #USE_CCACHE=1 8 | 9 | # where downloaded files are stored 10 | #SRCDEST=/var/cache/distfiles 11 | 12 | # uncomment line below to store built packages in other location 13 | # The package will be stored as $REPODEST/$repo/$arch/$pkgname-$pkgver-r$pkgrel.apk 14 | # where $repo is the name of the parent directory of $startdir. 15 | #REPODEST=$HOME/packages/ 16 | 17 | # PACKAGER and MAINTAINER are used by newapkbuild when creating new aports for 18 | # the APKBUILD's "Contributor:" and "Maintainer:" comments, respectively. 19 | #PACKAGER="Your Name " 20 | #MAINTAINER="$PACKAGER" 21 | 22 | # what to clean up after a successful build 23 | #CLEANUP="srcdir bldroot pkgdir deps" 24 | 25 | # what to cleanup after a failed build 26 | #ERROR_CLEANUP="bldroot deps" 27 | 28 | # uncomment to prevent using global cache directories for Go and Cargo 29 | #MOVE_CACHES=1 30 | -------------------------------------------------------------------------------- /abump.1.scd: -------------------------------------------------------------------------------- 1 | abump(1) 2 | 3 | # NAME 4 | 5 | *abump* - bump pkgver in an APKBUILD file 6 | 7 | # SYNOPSIS 8 | 9 | *abump* [-s _CVE-1_,...] [-f _ISSUE_] [-b|--branch] [-k|--keep] _PKGNAME-1.2.3_ 10 | 11 | # DESCRIPTION 12 | 13 | *abump* updates the *pkgver* in an APKBUILD file, updates its checksums, 14 | rebuilds it, and finally creates a new commit commit with the changes resulting. 15 | 16 | *abump* looks for the specified package in nested directories inside the current 17 | working directory, assuming a layout like that of the aports repository. 18 | 19 | # OPTIONS 20 | 21 | *-s, --security CVE1,...* 22 | Include CVE in the *secfixes* comment section. 23 | 24 | *-f, --fixes ISSUE* 25 | Include *Fixes #ISSUE* in the commit message. This will close the upstream 26 | issue when the commit is merged into the aports master branch. 27 | 28 | *-b, --branch* 29 | Create a git branch from HEAD before normal operation. 30 | 31 | *-k, --keep* 32 | Keep existing packages. 33 | 34 | *-h, --help* 35 | Print help information and exit. 36 | 37 | # ENVIRONMENT 38 | 39 | APORTSDIR 40 | Force operating on an alternate directory. 41 | 42 | # EXAMPLES 43 | 44 | ``` 45 | abump mml-1.0.0 46 | abump glibmm2.68-2.78.0 47 | abump telegram-desktop-4.11.8 48 | ``` 49 | 50 | # SEE ALSO 51 | 52 | abuild(1), apkgrel(1), newapkbuild(1), APKBUILD(5), apk(8). 53 | 54 | # AUTHORS 55 | 56 | Natanael Copa <_ncopa@alpinelinux.org_> and open source contributors. 57 | -------------------------------------------------------------------------------- /abump.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # abump - bump pkgver in APKBUILDs 4 | # Copyright (c) 2012 Natanael Copa 5 | # 6 | # Distributed under GPL-2.0-only 7 | # 8 | 9 | program_version=@VERSION@ 10 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 11 | 12 | if ! [ -f "$sharedir/functions.sh" ]; then 13 | echo "$sharedir/functions.sh: not found" >&2 14 | exit 1 15 | fi 16 | . "$sharedir/functions.sh" 17 | 18 | : ${ABUILD:="abuild"} 19 | 20 | 21 | # version bump packages 22 | do_bump() { 23 | local p rc=0 notbumped="" name ver section message 24 | local upgrade="${cvelist:+security }upgrade" 25 | local a 26 | for p; do 27 | if [ $rc -gt 0 ]; then 28 | notbumped="$notbumped $p" 29 | continue 30 | fi 31 | name=${p%-[0-9]*} 32 | ver=${p#${name}-} 33 | if [ "$name" = "$ver" ]; then 34 | die "version missing for $p" 35 | fi 36 | 37 | ( 38 | set -e 39 | 40 | # calculate APKBUILD's path #vim syntax highlight ' 41 | if [ "${name#*/}" != "$name" ] && ! [ -d "$APORTSDIR/${name%/*}" ]; then 42 | die "'$p' should be of form 'foo-1.2.3' or 'main/foo-1.2.3'" 43 | fi 44 | a=$(aports_buildscript "$name" ) \ 45 | || die "can't find APKBUILD for $name" 46 | 47 | # sourcing APKBUILDs should not affect the environment of abump 48 | # so do that in a subshell, along with any checks that need the 49 | # information from the APKBUILD. 50 | ( 51 | # verify APKBUILD 52 | . "$a" || exit 1 53 | name=${name#*/} 54 | [ "$pkgname" = "$name" ] \ 55 | || die "APKBUILD has different \$pkgname for $name" 56 | type package | grep -q function \ 57 | || die "missing package() for $name" 58 | if [ "$pkgver" = "$ver" ] && git diff-index --quiet HEAD -- "$a"; then 59 | die "version is already $ver" 60 | fi 61 | ) 62 | 63 | cd "${a%/*}" 64 | section=${PWD%/*} 65 | section=${section##*/} 66 | 67 | message="$section/$name: $upgrade to ${ver}${cvelist}" 68 | if [ -n "$fixes" ]; then 69 | message="$message 70 | 71 | fixes #${fixes#\#} 72 | " 73 | fi 74 | msg "$message" 75 | 76 | sed -i -e "s/^pkgver=[^ ]*/pkgver=$ver/" \ 77 | -e "s/^pkgrel=[^ ]*/pkgrel=0/" \ 78 | APKBUILD 79 | 80 | $ABUILD $abuild_opts checksum all 81 | checkapk 82 | 83 | git add APKBUILD 84 | git commit -m"$message" 85 | ) 86 | rc=$? 87 | if [ $rc -gt 0 ]; then 88 | error "Failed to build $p" 89 | fi 90 | done 91 | if [ -n "$notbumped" ]; then 92 | error "Not bumped: $notbumped" 93 | fi 94 | return $rc 95 | } 96 | 97 | usage() { 98 | cat <<-__EOF__ 99 | $program $program_version - bump pkgver in APKBUILDs 100 | Usage: $program [-s CVE-1,CVE-2,...] [-f ISSUE] [-b|--branch] [-k|--keep] PKGNAME-1.2.3 ... 101 | Options: 102 | -s, --security CVE1,CVE-2,... Security update 103 | -f, --fixes ISSUE Fixes ISSUE 104 | -b, --branch Create a git branch from HEAD before normal operation 105 | -k, --keep Run abuild with -k to keep existing packages 106 | -q, --quiet 107 | -h, --help Show this help 108 | 109 | __EOF__ 110 | } 111 | 112 | keep= 113 | cvelist= 114 | fixes= 115 | branch= 116 | 117 | args=$(getopt -o f:s:bkqh --long fixes:,security:,branch,keep,quiet,help \ 118 | -n "$program" -- "$@") 119 | if [ $? -ne 0 ]; then 120 | usage >&2 121 | exit 2 122 | fi 123 | eval set -- "$args" 124 | while true; do 125 | case $1 in 126 | -s|--security) cvelist=" ($2)"; shift;; 127 | -f|--fixes) fixes="$2"; shift;; 128 | -b|--branch) branch=1;; 129 | -k|--keep) keep="-k";; 130 | -q|--quiet) quiet=1;; # suppresses msg 131 | -h|--help) usage; exit 0;; 132 | --) shift; break;; 133 | *) exit 1;; # getopt error 134 | esac 135 | shift 136 | done 137 | if [ $# -eq 0 ]; then 138 | usage >&2 139 | exit 2 140 | fi 141 | 142 | [ -n "$APORTSDIR" ] || error "can't locate \$APORTSDIR" 143 | git rev-parse 2>/dev/null || die "not in a git tree" 144 | if [ "$branch" = 1 ]; then 145 | git checkout -b "bump-$1" 146 | fi 147 | 148 | abuild_opts="${ABUILD_OPTS- -r} $keep" 149 | 150 | do_bump "$@" 151 | -------------------------------------------------------------------------------- /apkbuild-gem-resolver.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | # APKBUILD dependency resolver for RubyGems 4 | # Copyright (C) 2014-2016 Kaarle Ritvanen 5 | 6 | require 'augeas' 7 | require 'optparse' 8 | require 'rubygems/dependency' 9 | require 'rubygems/resolver' 10 | require 'rubygems/spec_fetcher' 11 | 12 | class Package 13 | @@packages = {} 14 | 15 | def self.initialize level 16 | @@augeas = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD) 17 | dir = Dir.pwd 18 | @@augeas.transform( 19 | :lens => 'Shellvars.lns', :incl => dir + '/*/ruby*/APKBUILD' 20 | ) 21 | @@augeas.load 22 | 23 | apath = '/files' + dir 24 | fail unless @@augeas.match("/augeas#{apath}//error").empty? 25 | 26 | repos = ['main', 'community', 'testing'] 27 | repos = repos[0..repos.index(level)] 28 | for repo in repos 29 | for pkg in @@augeas.match "#{apath}/#{repo}/*" 30 | Aport.new(pkg) unless pkg.end_with? '/ruby' 31 | end 32 | end 33 | 34 | Subpackage.initialize @@augeas.get("#{apath}/main/ruby/APKBUILD/pkgver") 35 | 36 | @@packages.each_value do |pkg| 37 | pkg.depends do |dep| 38 | dep.add_user pkg 39 | end 40 | end 41 | end 42 | 43 | def self.get name 44 | pkg = @@packages[name] 45 | raise 'Invalid package name: ' + name unless pkg 46 | pkg 47 | end 48 | 49 | def self.save 50 | fail unless @@augeas.save 51 | end 52 | 53 | def initialize name 54 | @name = name 55 | @depends = [] 56 | @users = [] 57 | @@packages[name] = self 58 | end 59 | 60 | def add_dependency name 61 | @depends << name 62 | end 63 | 64 | attr_reader :name 65 | 66 | def depends 67 | for dep in @depends 68 | # ruby-gems: workaround for v2.6 69 | if dep.start_with?('ruby-') && dep != 'ruby-gems' 70 | unless @@packages.has_key? dep 71 | raise "Dependency for #{@name} does not exist: #{dep}" 72 | end 73 | yield @@packages[dep] 74 | end 75 | end 76 | end 77 | 78 | def users 79 | for user in @users 80 | yield user 81 | end 82 | end 83 | 84 | def add_user user 85 | @users << user 86 | end 87 | end 88 | 89 | class Aport < Package 90 | def initialize path 91 | super path.split('/')[-1] 92 | 93 | @path = path[6..-1] 94 | @apath = path + '/APKBUILD/' 95 | 96 | for dep in `echo #{get_param 'depends'}`.split 97 | add_dependency dep 98 | end 99 | end 100 | 101 | attr_reader :path 102 | 103 | def gem 104 | get_param '_gemname' 105 | end 106 | 107 | def version 108 | get_param 'pkgver' 109 | end 110 | 111 | def version= version 112 | set_param 'pkgver', version 113 | set_param 'pkgrel', '0' 114 | end 115 | 116 | def del_dependency name 117 | @depends.delete name 118 | set_param 'depends', "\"#{@depends.join ' '}\"" 119 | end 120 | 121 | private 122 | 123 | def get_param name 124 | value = @@augeas.get(@apath + name) 125 | raise name + ' not defined for ' + @name unless value 126 | value 127 | end 128 | 129 | def set_param name, value 130 | @@augeas.set(@apath + name, value) 131 | end 132 | end 133 | 134 | class Subpackage < Package 135 | RUBY_SUBPACKAGES = { 136 | '2.0.0_p353' => { 137 | 'ruby-minitest' => ['minitest', '4.3.2'], 138 | 'ruby-rake' => ['rake', '0.9.6'], 139 | 'ruby-rdoc' => ['rdoc', '4.0.0', 'ruby-json'] 140 | }, 141 | '2.0.0_p481' => { 142 | 'ruby-minitest' => ['minitest', '4.3.2'], 143 | 'ruby-rake' => ['rake', '0.9.6'], 144 | 'ruby-rdoc' => ['rdoc', '4.0.0', 'ruby-json'] 145 | }, 146 | '2.1.5' => { 147 | 'ruby-json' => ['json', '1.8.1'], 148 | 'ruby-minitest' => ['minitest', '4.7.5'], 149 | 'ruby-rake' => ['rake', '10.1.0'], 150 | 'ruby-rdoc' => ['rdoc', '4.1.0', 'ruby-json'] 151 | }, 152 | '2.2.1' => { 153 | # it's actually 0.4.3 but that version is not published on network 154 | 'ruby-io-console' => ['io-console', '0.4.2'], 155 | 'ruby-json' => ['json', '1.8.1'], 156 | 'ruby-minitest' => ['minitest', '5.4.3'], 157 | 'ruby-rake' => ['rake', '10.4.2'], 158 | 'ruby-rdoc' => ['rdoc', '4.2.0', 'ruby-json'] 159 | }, 160 | '2.2.2' => { 161 | # it's actually 0.4.3 but that version is not published on network 162 | 'ruby-io-console' => ['io-console', '0.4.2'], 163 | 'ruby-json' => ['json', '1.8.1'], 164 | 'ruby-minitest' => ['minitest', '5.4.3'], 165 | 'ruby-rake' => ['rake', '10.4.2'], 166 | 'ruby-rdoc' => ['rdoc', '4.2.0', 'ruby-json'] 167 | }, 168 | '2.2.3' => { 169 | # it's actually 0.4.3 but that version is not published on network 170 | 'ruby-io-console' => ['io-console', '0.4.2'], 171 | 'ruby-json' => ['json', '1.8.1'], 172 | 'ruby-minitest' => ['minitest', '5.4.3'], 173 | 'ruby-rake' => ['rake', '10.4.2'], 174 | 'ruby-rdoc' => ['rdoc', '4.2.0', 'ruby-json'] 175 | }, 176 | '2.2.4' => { 177 | # it's actually 0.4.3 but that version is not published on network 178 | 'ruby-io-console' => ['io-console', '0.4.2'], 179 | 'ruby-json' => ['json', '1.8.1'], 180 | 'ruby-minitest' => ['minitest', '5.4.3'], 181 | 'ruby-rake' => ['rake', '10.4.2'], 182 | 'ruby-rdoc' => ['rdoc', '4.2.0', 'ruby-json'] 183 | } 184 | } 185 | 186 | @@subpackages = [] 187 | 188 | def self.initialize version 189 | for name, attrs in RUBY_SUBPACKAGES[version] 190 | new name, attrs 191 | end 192 | end 193 | 194 | def self.each 195 | for pkg in @@subpackages 196 | yield pkg 197 | end 198 | end 199 | 200 | def initialize name, attrs 201 | super name 202 | @gem, @version, *deps = attrs 203 | for dep in deps 204 | add_dependency dep 205 | end 206 | @@subpackages << self 207 | end 208 | 209 | attr_reader :gem, :version 210 | end 211 | 212 | 213 | class Update 214 | def initialize 215 | @gems = {} 216 | @deps = [] 217 | end 218 | 219 | def require_version name, version 220 | gem = assign(Package.get(name).gem, name) 221 | @deps << gem.dependency if gem.require_version version 222 | end 223 | 224 | def resolve 225 | for pkg in Subpackage 226 | require_version pkg.name, pkg.version unless @gems[pkg.gem] 227 | end 228 | 229 | def check_deps 230 | @gems.clone.each_value do |gem| 231 | gem.check_deps 232 | end 233 | end 234 | 235 | check_deps 236 | 237 | for req in Gem::Resolver.new(@deps).resolve 238 | spec = req.spec 239 | gem = @gems[spec.name] 240 | gem.require_version spec.version.version if gem 241 | end 242 | 243 | check_deps 244 | 245 | for name, gem in @gems 246 | if gem.updated? 247 | gem.package.users do |user| 248 | ugem = @gems[user.gem] 249 | if !ugem || ugem.package.name != user.name 250 | Gem::Resolver.new( 251 | [gem.dependency, Gem::Dependency.new(user.gem, user.version)] 252 | ).resolve 253 | end 254 | end 255 | end 256 | end 257 | end 258 | 259 | def each 260 | @gems.each_value do |gem| 261 | update = gem.update 262 | yield update if update 263 | end 264 | end 265 | 266 | def assign name, package 267 | pkg = Package.get package 268 | 269 | if @gems.has_key? name 270 | gem = @gems[name] 271 | return gem if pkg == gem.package 272 | raise "Conflicting packages for gem #{name}: #{gem.package.name} and #{pkg.name}" 273 | end 274 | 275 | gem = PackagedGem.new self, name, pkg 276 | @gems[name] = gem 277 | gem 278 | end 279 | 280 | private 281 | 282 | class PackagedGem 283 | def initialize update, name, package 284 | @update = update 285 | @name = name 286 | @package = package 287 | end 288 | 289 | attr_reader :package 290 | 291 | def require_version version 292 | if @version 293 | return false if version == @version 294 | raise "Conflicting versions for gem #{@name}: #{@version} and #{version}" 295 | end 296 | @version = version 297 | true 298 | end 299 | 300 | def version 301 | @version || @package.version 302 | end 303 | 304 | def updated? 305 | version != @package.version 306 | end 307 | 308 | def dependency 309 | Gem::Dependency.new(@name, version) 310 | end 311 | 312 | def check_deps 313 | specs, errors = Gem::SpecFetcher::fetcher.spec_for_dependency(dependency) 314 | raise "Invalid gem: #{@name}-#{version}" if specs.empty? 315 | fail if specs.length > 1 316 | deps = specs[0][0].runtime_dependencies 317 | 318 | @obsolete_deps = [] 319 | 320 | @package.depends do |dep| 321 | gem = @update.assign(dep.gem, dep.name) 322 | gem.check_deps 323 | unless deps.reject! { |sdep| sdep.match? dep.gem, gem.version } 324 | @obsolete_deps << dep.name 325 | end 326 | end 327 | 328 | unless deps.empty? 329 | raise 'Undeclared dependencies in ' + @package.name + deps.inject('') { 330 | |s, dep| "#{s}\n#{dep.name} #{dep.requirements_list.join ' '}" 331 | } 332 | end 333 | end 334 | 335 | def update 336 | updated? || !@obsolete_deps.empty? ? ( 337 | { 338 | :name => @package.name, 339 | :version => version, 340 | :obsolete_deps => @obsolete_deps.clone, 341 | :path => @package.path 342 | } 343 | ) : nil 344 | end 345 | end 346 | end 347 | 348 | 349 | level = 'main' 350 | update_files = nil 351 | OptionParser.new do |opts| 352 | opts.on('-c', '--community') do |c| 353 | level = 'community' 354 | end 355 | opts.on('-t', '--testing') do |t| 356 | level = 'testing' 357 | end 358 | opts.on('-u', '--update') do |u| 359 | update_files = [] 360 | end 361 | end.parse! ARGV 362 | Package.initialize level 363 | 364 | latest = {} 365 | for source, gems in Gem::SpecFetcher::fetcher.available_specs(:latest)[0] 366 | for gem in gems 367 | latest[gem.name] = gem.version.version 368 | end 369 | end 370 | 371 | update = Update.new 372 | for arg in ARGV 373 | match = /^(([^-]|-[^\d])+)(-(\d.*))?/.match arg 374 | name = match[1] 375 | update.require_version name, match[4] || latest[Package.get(name).gem] 376 | end 377 | 378 | update.resolve 379 | 380 | for pkg in update 381 | obsolete = pkg[:obsolete_deps] 382 | 383 | obs = obsolete.empty? ? 384 | nil : " (obsolete dependencies: #{obsolete.join ', '})" 385 | puts "#{pkg[:name]}-#{pkg[:version]}#{obs}" 386 | 387 | if update_files 388 | package = Package.get(pkg[:name]) 389 | package.version = pkg[:version] 390 | for dep in obsolete 391 | package.del_dependency dep 392 | end 393 | update_files << pkg[:path] 394 | end 395 | end 396 | 397 | if update_files 398 | Package.save 399 | 400 | for path in update_files 401 | Dir.chdir(path) do 402 | fail unless system('abuild checksum') 403 | end 404 | end 405 | end 406 | -------------------------------------------------------------------------------- /apkbuild-pypi.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | use autodie qw(:all); 6 | use feature qw(:5.14); 7 | use LWP::UserAgent; 8 | use LWP::ConnCache; 9 | use JSON; 10 | use URI; 11 | use Text::Wrap qw(wrap $columns); 12 | use File::Basename qw(dirname); 13 | 14 | our $packager = ''; 15 | my %pkgmap = (); 16 | my %licenses = (); 17 | 18 | my $template = <<'EOF'; 19 | # Automatically generated by apkbuild-pypi, template 4 20 | [% authors %] 21 | pkgname=[% pkgname %] 22 | pkgver=[% pkgver %] 23 | pkgrel=[% pkgrel %] 24 | # _pkgreal is used by apkbuild-pypi to find modules at PyPI 25 | _pkgreal=[% pkgreal %] 26 | pkgdesc="[% pkgdesc %]" 27 | url="[% url %]" 28 | arch="noarch" 29 | license="[% license %]" 30 | depends="" 31 | makedepends="py3-gpep517 py3-setuptools py3-wheel" 32 | checkdepends="py3-pytest" 33 | subpackages="$pkgname-pyc" 34 | source="[% source %]" 35 | builddir="[% builddir %]" 36 | options="[% options %]"[% options_comment %] 37 | [% compatibility %] 38 | build() { 39 | gpep517 build-wheel \ 40 | --wheel-dir .dist \ 41 | --output-fd 3 3>&1 >&2 42 | } 43 | 44 | check() { 45 | python3 -m venv --clear --without-pip --system-site-packages .testenv 46 | .testenv/bin/python3 -m installer .dist/*.whl 47 | .testenv/bin/python3 -m pytest 48 | } 49 | 50 | package() { 51 | python3 -m installer -d "$pkgdir" \ 52 | .dist/*.whl 53 | } 54 | 55 | EOF 56 | 57 | my $ua = LWP::UserAgent->new(); 58 | my $json = JSON->new; 59 | $ua->env_proxy; 60 | $ua->conn_cache(LWP::ConnCache->new); 61 | 62 | sub read_file { 63 | my ($filename) = @_; 64 | open my $fh, '<:utf8', $filename; 65 | local $/; 66 | my $text = <$fh>; 67 | return $text; 68 | } 69 | 70 | sub read_assignments_from_file { 71 | my ($filename) = @_; 72 | return () if ( ! -e $filename ); 73 | my $text = read_file($filename); 74 | my %sline = $text =~ /^(\w+)\s*=\s*([^\"\n]*)$/mg; 75 | my %mline = $text =~ /^(\w+)\s*=\s*\"([^\"]*)\".*$/mg; 76 | my %hash = ( %sline, %mline ); 77 | 78 | return \%hash if $filename ne 'APKBUILD'; 79 | my $authors = join( "\n", 80 | $text =~ /^# Contributor: .*$/mg, 81 | $text =~ /^# Maintainer: .*$/mg ); 82 | $hash{'authors'} = $authors if length($authors) > 1; 83 | 84 | if ($text =~ m/^provides=\"(.*)\"(.*)$/m) { 85 | $hash{'provides'} = $1; 86 | $hash{'provides_comment'} = $2; 87 | } 88 | 89 | if ($text =~ m/^replaces=\"(.*)\"(.*)$/m) { 90 | $hash{'replaces'} = $1; 91 | $hash{'replaces_comment'} = $2; 92 | } 93 | 94 | # workaround for `builddir="$srcdir"/$_pkgname-$pkgver` 95 | if ($text =~ m/^builddir=\"(.*)\"([^\s]*)/m) { 96 | $hash{'builddir'} = $1 . $2; 97 | } 98 | 99 | if ($text =~ m/^options=\"(.*)\"(.*)$/m) { 100 | $hash{'options'} = $1; 101 | $hash{'options_comment'} = $2; 102 | } 103 | 104 | return \%hash; 105 | } 106 | 107 | sub map_pypi_to_apk { 108 | my ($pypi) = @_; 109 | return $pkgmap{$pypi} unless !exists($pkgmap{$pypi}); 110 | return 'py3-'.lc($pypi); 111 | } 112 | 113 | sub map_license { 114 | my ($license) = @_; 115 | 116 | $license //= ''; 117 | $license =~ s/ or / /g; 118 | 119 | return $license; 120 | } 121 | 122 | sub get_source { 123 | my ($distdata) = @_; 124 | my $pkgname = $distdata->{info}{name}; 125 | 126 | my $source; 127 | for my $url (@{$distdata->{urls}}) { 128 | if ($url->{python_version} eq 'source') { 129 | $source = URI->new($url->{url}); 130 | last; 131 | } 132 | } 133 | die "Unable to locate sources for $pkgname.\n" unless $source; 134 | 135 | my $filename = ($source->path_segments)[-1]; 136 | my $pretty_path = substr($pkgname, 0, 1) . "/$pkgname"; 137 | my $pretty_url = $source->clone; 138 | $pretty_url->path("/packages/source/$pretty_path/$filename"); 139 | 140 | my $response = $ua->head($pretty_url); 141 | if ($response->is_success) { 142 | return $pretty_url->as_string; 143 | } else { 144 | return $source->as_string; 145 | } 146 | } 147 | 148 | sub read_apkbuild { 149 | return read_assignments_from_file('APKBUILD'); 150 | } 151 | 152 | sub format_line { 153 | my $line = shift; 154 | return "\t" . $line . "\n"; 155 | } 156 | 157 | sub format_source { 158 | my $srcurl = shift; 159 | my $orig_src = shift; 160 | 161 | $orig_src =~ s/^\s+//mg; 162 | $orig_src =~ s/\s+/ /g; 163 | 164 | my @sources = split (/\s/, $orig_src); 165 | 166 | return $srcurl if @sources <= 1; 167 | 168 | shift @sources if $sources[0] =~ m/pkgver/; 169 | my $patches; 170 | for my $patch (@sources) { 171 | next if $patch eq ""; 172 | $patches .= format_line($patch); 173 | } 174 | 175 | return $srcurl . "\n" . ($patches // '') . "\t"; 176 | } 177 | 178 | sub write_apkbuild { 179 | my ($distdata, $apkbuild) = @_; 180 | 181 | my $replaces = undef; 182 | my $provides = undef; 183 | my $authors = undef; 184 | my $license = undef; 185 | my $url = undef; 186 | my $pkgname = undef; 187 | my $pkgdesc = undef; 188 | my $pkgrel = 0; 189 | my $builddir = undef; 190 | my $options = undef; 191 | my $options_comment = undef; 192 | my $orig_source = ""; 193 | 194 | if (our $use_homepage) { 195 | $url = 196 | $distdata->{info}{project_urls}{Homepage} 197 | || $distdata->{info}{home_page}; 198 | } 199 | 200 | if (defined $apkbuild) { 201 | $authors = $apkbuild->{authors}; 202 | $provides = $apkbuild->{provides}; 203 | $replaces = $apkbuild->{replaces}; 204 | $license = $apkbuild->{license}; 205 | $url = $apkbuild->{url}; 206 | $pkgname = $apkbuild->{pkgname}; 207 | $pkgdesc = $apkbuild->{pkgdesc}; 208 | $pkgrel = $apkbuild->{pkgrel}; 209 | $builddir = $apkbuild->{builddir}; 210 | $options = $apkbuild->{options} if defined $apkbuild->{options}; 211 | $options_comment = $apkbuild->{options_comment} if defined $apkbuild->{options_comment}; 212 | $orig_source = $apkbuild->{source}; 213 | 214 | if ($apkbuild->{pkgver} eq $distdata->{info}{version}) { 215 | $pkgrel++; 216 | } 217 | } 218 | 219 | my $pkgreal = $distdata->{info}{name}; 220 | my $srcurl = get_source($distdata); 221 | 222 | my %repl = ( 223 | authors => ($authors or "# Contributor: $packager\n# Maintainer: $packager"), 224 | pkgname => ($pkgname or map_pypi_to_apk($pkgreal)), 225 | pkgreal => $pkgreal, 226 | pkgver => $distdata->{info}{version}, 227 | pkgrel => $pkgrel, 228 | source => format_source($srcurl, $orig_source), 229 | license => ($license or map_license($distdata->{info}{license})), 230 | url => ($url or "https://pypi.org/project/${pkgreal}/"), 231 | pkgdesc => ($pkgdesc or $distdata->{info}{summary} or "Python module for $pkgreal"), 232 | builddir => ($builddir or ''), 233 | options => ($options or ''), 234 | options_comment => ($options_comment or ''), 235 | ); 236 | 237 | $repl{compatibility} = ""; 238 | if ($replaces) { 239 | my $comment = $apkbuild->{'replaces_comment'} // ''; 240 | $repl{compatibility} .= "\nreplaces=\"$replaces\"" . $comment; 241 | } 242 | if ($provides) { 243 | my $comment = $apkbuild->{'provides_comment'} // ''; 244 | $repl{compatibility} .= "\nprovides=\"$provides\"" . $comment; 245 | } 246 | $repl{compatibility} .= "\n" if $replaces or $provides; 247 | 248 | $repl{source} =~ s/-$repl{pkgver}/-\$pkgver/g; 249 | $template =~ s/\[% (.*?) %\]/$repl{$1}/g; 250 | 251 | open my $fh, '>:utf8', 'APKBUILD'; 252 | print {$fh} $template; 253 | close $fh; 254 | 255 | say "Wrote $repl{pkgname}/APKBUILD"; 256 | 257 | return \%repl; 258 | } 259 | 260 | sub unpack_source { 261 | system('abuild checksum unpack'); 262 | } 263 | 264 | sub prepare_tree { 265 | my %options = @_; 266 | 267 | unpack_source if $options{unpack}; 268 | system('abuild prepare'); 269 | } 270 | 271 | sub find_package_name { 272 | my ($apkbuild) = @_; 273 | 274 | my $pkgreal = ''; 275 | 276 | if (exists $apkbuild->{_realname}) { 277 | $pkgreal = $apkbuild->{_realname}; 278 | } elsif (exists $apkbuild->{_pkgreal}) { 279 | $pkgreal = $apkbuild->{_pkgreal}; 280 | } elsif (exists $apkbuild->{_pkgname}) { 281 | $pkgreal = $apkbuild->{_pkgname}; 282 | } elsif (exists $apkbuild->{_name}) { 283 | $pkgreal = $apkbuild->{_name}; 284 | } elsif (exists $apkbuild->{_realpkgname}) { 285 | $pkgreal = $apkbuild->{_realpkgname}; 286 | } elsif (exists $apkbuild->{_pkg_real}) { 287 | $pkgreal = $apkbuild->{_pkg_real}; 288 | } elsif (exists $apkbuild->{source}) { 289 | $pkgreal = $apkbuild->{source}; 290 | $pkgreal =~ m/(\w+)-/; 291 | $pkgreal = $1; 292 | } else { 293 | print "No pkg real found\n"; 294 | die; 295 | } 296 | return $pkgreal; 297 | } 298 | 299 | sub get_data { 300 | my ($package) = @_; 301 | my $response = $ua->get("https://pypi.org/pypi/$package/json"); 302 | $response->is_success or die $response->status_line; 303 | my $distdata = $json->decode($response->decoded_content); 304 | 305 | return $distdata; 306 | } 307 | 308 | sub parse_requires_dist { 309 | my $reqs = shift; 310 | 311 | # Valid PyPI regex: https://peps.python.org/pep-0508/#names 312 | my $pypi_regex = qr/(?i)([A-Z0-9][A-Z0-9][A-Z0-9._-]*[A-Z0-9])/; 313 | 314 | my @depends = 315 | map { m/$pypi_regex/; $1 || () } 316 | grep { $_ !~ m/; extra ==/ } 317 | @$reqs; 318 | 319 | my @checkdeps = 320 | map { m/$pypi_regex/; $1 || () } 321 | grep { m/; extra == ["'](tests|pytest)["']/ } 322 | @$reqs; 323 | 324 | my %reqs = ( 325 | depends => \@depends, 326 | checkdeps => \@checkdeps, 327 | ); 328 | 329 | return \%reqs; 330 | } 331 | 332 | sub format_depends { 333 | my $deps = shift; 334 | 335 | $columns = 102; 336 | 337 | $deps =~ s/ {2,}/ /g; 338 | $deps =~ s/^\s//g; 339 | $deps =~ s/\s$//g; 340 | 341 | if ( length($deps) >= $columns ) { 342 | $deps = wrap( "\t", "\t", $deps ); 343 | } 344 | $deps =~ s/\s$//g; 345 | 346 | if ( length($deps) >= $columns ) { 347 | $deps = "\n" . $deps . "\n\t"; 348 | } 349 | return $deps; 350 | } 351 | 352 | sub get_deps { 353 | my ($distdata, $data) = @_; 354 | 355 | my $reqs = parse_requires_dist($distdata->{info}{requires_dist}); 356 | my %depends = ('py3-pytest' => 'py3-pytest'); 357 | 358 | my @depends = 359 | map { 360 | my $apkname = map_pypi_to_apk($_); 361 | if (exists $depends{$apkname}) { () } 362 | else { $depends{$apkname} = $apkname } 363 | } 364 | @{$reqs->{depends}}; 365 | 366 | my @checkdeps = 367 | map { 368 | my $apkname = map_pypi_to_apk($_); 369 | exists($depends{$apkname}) ? () : $apkname 370 | } 371 | @{$reqs->{checkdeps}}; 372 | 373 | my $apk = read_file('APKBUILD'); 374 | 375 | my $depends = format_depends(join ' ', @depends); 376 | 377 | $apk =~ s/^depends=""/depends="$depends"/m; 378 | 379 | unshift @checkdeps, 'py3-pytest'; 380 | my $checkdeps = format_depends(join ' ', @checkdeps); 381 | 382 | $apk =~ s/^checkdepends="py3-pytest"/checkdepends="$checkdeps"/m; 383 | 384 | # remove empty variables 385 | $apk =~ s/.*="".{0,}\n//g; 386 | 387 | open my $fh, '>:utf8', 'APKBUILD'; 388 | 389 | print $fh $apk; 390 | 391 | say "Requires: @depends\n\nCheckDepends: @checkdeps"; 392 | } 393 | 394 | sub write_old_deps { 395 | my ($data, $apkbuild) = @_; 396 | 397 | my $apk = read_file('APKBUILD'); 398 | 399 | if (my $depends = $apkbuild->{depends}) { 400 | $apk =~ s/^depends=".*"/depends="$depends"/m; 401 | } 402 | 403 | if (my $makedeps = $apkbuild->{makedepends}) { 404 | if ($makedeps =~ m/py3-gpep517/) { 405 | $apk =~ s/^makedepends=".*"/makedepends="$makedeps"/m; 406 | } else { 407 | $apk =~ s/^makedepends="(.*)"/makedepends="$1 $makedeps"/m; 408 | } 409 | } 410 | 411 | if (my $checkdeps = $apkbuild->{checkdepends}) { 412 | if ($checkdeps =~ m/py3-pytest/) { 413 | $apk =~ s/^checkdepends=".*"/checkdepends="$checkdeps"/m; 414 | } else { 415 | $apk =~ s/^checkdepends="(.*)"/checkdepends="$1 $checkdeps"/m; 416 | } 417 | } 418 | 419 | # remove empty variables 420 | $apk =~ s/.*="".{0,}\n//g; 421 | 422 | open my $fh, '>:utf8', 'APKBUILD'; 423 | 424 | print $fh $apk; 425 | } 426 | 427 | sub update_builddir { 428 | my $apkbuild = read_apkbuild; 429 | my $pkgreal = $apkbuild->{'_pkgreal'}; 430 | my $pkgname = $apkbuild->{pkgname}; 431 | my $pkgver = $apkbuild->{pkgver}; 432 | my $oldbuilddir = $apkbuild->{builddir}; 433 | 434 | my $build_path = glob(" 435 | src/*${pkgver}/pyproject.toml 436 | src/*${pkgver}/setup.py 437 | "); 438 | 439 | if ($build_path) { 440 | my $newbuilddir = dirname($build_path); 441 | 442 | $newbuilddir =~ s/src/\$srcdir/; 443 | $newbuilddir =~ s/$pkgreal/\$_pkgreal/; 444 | $newbuilddir =~ s/$pkgver/\$pkgver/; 445 | 446 | my $apk = read_file('APKBUILD'); 447 | 448 | if ($pkgname eq $pkgreal and 449 | $newbuilddir eq '$srcdir/$_pkgreal-$pkgver') { 450 | # this will be deleted by the remove empty 451 | # variables regex in get_deps/write_old_deps 452 | $apk =~ s/^builddir=".*"/builddir=""/m; 453 | 454 | $newbuilddir = ''; 455 | } elsif ($newbuilddir eq $oldbuilddir) { 456 | return; 457 | } else { 458 | $apk =~ s/^builddir=".*"/builddir="$newbuilddir"/m; 459 | } 460 | 461 | print "\n\$builddir redefined:\n\t", 462 | "OLD: $oldbuilddir, NEW: $newbuilddir\n\n"; 463 | 464 | open my $fh, '>:utf8', 'APKBUILD'; 465 | print $fh $apk; 466 | } 467 | } 468 | 469 | my $abuild_conf = read_assignments_from_file('/etc/abuild.conf'); 470 | $packager = $abuild_conf->{PACKAGER} if $abuild_conf->{PACKAGER}; 471 | 472 | my $user_abuild_conf = read_assignments_from_file($ENV{"HOME"} . "/.abuild/abuild.conf"); 473 | $packager = $user_abuild_conf->{PACKAGER} if $user_abuild_conf->{PACKAGER}; 474 | 475 | sub usage { 476 | say <<'EOF'; 477 | Usage: apkbuild-pypi [create [homepage] | check | recreate [deps] | upgrade | update] 478 | 479 | In the repository root: 480 | create : Creates an APKBUILD for 481 | create homepage: Creates an APKBUILD for with url= field set to project homepage, if available 482 | 483 | In the package root: 484 | check : Reports current & latest version of the package 485 | recreate [deps] : Recreates the APKBUILD [also recalculate dependencies] 486 | upgrade : Upgrades to the latest version of the package 487 | update : Updates APKBUILD metadata 488 | EOF 489 | } 490 | 491 | if (! defined $ARGV[0]) { 492 | die usage; 493 | } elsif ($ARGV[0] eq 'create') { 494 | my $package = $ARGV[1]; 495 | $package or die usage; 496 | 497 | my $distdata = get_data($package); 498 | my $apkname = map_pypi_to_apk($package); 499 | 500 | mkdir $apkname; 501 | chdir $apkname; 502 | 503 | if ($ARGV[2] and $ARGV[2] eq 'homepage') { our $use_homepage = 1; } 504 | 505 | my $data = write_apkbuild($distdata, undef); 506 | unpack_source; 507 | update_builddir; 508 | 509 | get_deps($distdata, $data); 510 | prepare_tree( unpack => 0 ); 511 | } elsif ($ARGV[0] eq 'recreate') { 512 | my $apkbuild = read_apkbuild; 513 | if (! defined $apkbuild->{_pkgreal}) { 514 | $apkbuild->{_pkgreal} = find_package_name($apkbuild); 515 | } 516 | my $distdata = get_data($apkbuild->{_pkgreal}); 517 | my $pkgver = $distdata->{info}{version} =~ s/^[^0-9]+//r; 518 | if ($pkgver ne $apkbuild->{pkgver}) { 519 | #Reset pkgrel on upgrade on recreate 520 | say "Upgrading PyPI module from $apkbuild->{pkgver} to $pkgver"; 521 | $apkbuild->{pkgrel}=0; 522 | } 523 | 524 | my $data = write_apkbuild($distdata, $apkbuild); 525 | unpack_source; 526 | update_builddir; 527 | 528 | if ($ARGV[1] and $ARGV[1] eq 'deps') { get_deps($distdata, $data); } 529 | else { write_old_deps($data, $apkbuild); } 530 | prepare_tree( unpack => 0 ); 531 | } elsif ($ARGV[0] eq 'upgrade') { 532 | my $apkbuild = read_apkbuild; 533 | 534 | if (! defined $apkbuild->{_pkgreal}) { 535 | $apkbuild->{_pkgreal} = find_package_name($apkbuild); 536 | } 537 | 538 | my $distdata = get_data($apkbuild->{_pkgreal}); 539 | 540 | my $pkgver = $distdata->{info}{version}; 541 | 542 | if ($pkgver ne $apkbuild->{pkgver}) { 543 | say "Upgrading PyPI package from $apkbuild->{pkgver} to $pkgver"; 544 | 545 | my $text = read_file('APKBUILD'); 546 | 547 | $text =~ s/^(pkgver)=.*$/$1=$pkgver/mg or 548 | die "Can't find pkgver line in APKBUILD"; 549 | $text =~ s/^(pkgrel)=.*$/$1=0/mg or 550 | die "Can't find pkgrel line in APKBUILD"; 551 | 552 | open my $fh, '>:utf8', 'APKBUILD'; 553 | print $fh $text; 554 | close $fh; 555 | } else { 556 | say "Already up to date with PyPI"; 557 | } 558 | } elsif ($ARGV[0] eq 'check') { 559 | my $apkbuild = read_apkbuild; 560 | 561 | if (! defined $apkbuild->{_pkgreal}) { 562 | $apkbuild->{_pkgreal} = find_package_name($apkbuild); 563 | } 564 | my $distdata = get_data($apkbuild->{_pkgreal}); 565 | 566 | my $pkgver = $distdata->{info}{version}; 567 | 568 | 569 | say "$apkbuild->{pkgname}: Latest version: $pkgver Packaged version: $apkbuild->{pkgver}"; 570 | if ($pkgver ne $apkbuild->{pkgver}) { 571 | exit(1); 572 | } 573 | } elsif ($ARGV[0] eq 'update') { 574 | prepare_tree( unpack => 1 ); 575 | } else { 576 | die usage; 577 | } 578 | -------------------------------------------------------------------------------- /apkgrel.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # apkgrel - display or bump pkgrel in APKBUILDs 4 | # Copyright (c) 2012 Natanael Copa 5 | # 6 | # Distributed under GPL-2.0-only 7 | # 8 | 9 | program_version=@VERSION@ 10 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 11 | 12 | if ! [ -f "$sharedir/functions.sh" ]; then 13 | echo "$sharedir/functions.sh: not found" >&2 14 | exit 1 15 | fi 16 | . "$sharedir/functions.sh" 17 | 18 | 19 | show_plain() { 20 | # we source the APKBUILD and show last pkgrel that's read 21 | # if this script is invoked with --force, this needn't pass "do_verify" 22 | ( . "$1" && echo "$pkgrel" ) 23 | } 24 | 25 | show_pretty() { 26 | ( 27 | . "$1" || exit 1 28 | [ -n "$pkgname" ] || die "no \$pkgname for $1" 29 | printf '%s: r%s\n' "$pkgname" "${pkgrel:-?}" 30 | ) 31 | } 32 | 33 | do_show() { 34 | local f= 35 | # show_pretty is more informative, but would change the output format of this script 36 | for f; do show_plain "$f"; done 37 | } 38 | 39 | do_set() { 40 | sed -e "/^pkgrel=/s/=.*/=${setto:-0}/" \ 41 | -i "$@" 42 | } 43 | 44 | do_add () { 45 | local f= old= 46 | for f; do 47 | [ -n "$only_clean_git" ] \ 48 | && [ -n "$(git diff --name-only -- "${f%/*}")" ] \ 49 | && continue 50 | old=$(show_plain "$f") 51 | case $old in 52 | [0-9]*) setto=$((old + 1));; 53 | *) setto=0;; 54 | esac 55 | do_set "$f" || return 1 56 | done 57 | } 58 | 59 | do_verify() { 60 | [ -n "$force" ] && return 0 61 | local f= rc=0 62 | for f; do 63 | if ! grep -q '^pkgrel=[0-9]' "$f"; then 64 | error "no proper \$pkgrel for $f" 65 | rc=1 66 | fi 67 | done 68 | return $rc 69 | } 70 | 71 | do_nothing() { 72 | return 0 73 | } 74 | 75 | usage() { 76 | cat <<-__EOF__ 77 | $program $program_version - display or bump pkgrel in APKBUILDs 78 | usage: $program [-z|--zero] [-a|--add] [-g|--clean-git] [-s|--set NUM] 79 | [-t|--test] [-f|--force] DIR or APKBUILD... 80 | Options: 81 | -z, --zero Set pkgrel to 0 82 | -a, --add Add 1 to current pkgrel 83 | -g, --clean-git Only operate on APKBUILDs with clean git status (implies 84 | --add) 85 | -s, --set NUM Set pkgrel to NUM 86 | -t, --test Only verify that files have a valid pkgrel 87 | -f, --force Operate on files without a valid pkgrel 88 | -h, --help Show this help 89 | 90 | __EOF__ 91 | } 92 | 93 | cmd=do_show 94 | force= 95 | setto= 96 | only_clean_git= 97 | 98 | args=$(getopt -o zags:tfqh --long zero,add,clean-git,set:,test,force,quiet,help \ 99 | -n "$program" -- "$@") 100 | if [ $? -ne 0 ]; then 101 | usage >&2 102 | exit 2 103 | fi 104 | eval set -- "$args" 105 | while true; do 106 | case $1 in 107 | -z|--zero) setto=0; cmd=do_set;; 108 | -a|--add) cmd=do_add;; 109 | -g|--clean-git) # verify that we're in a git tree 110 | git rev-parse 2>/dev/null || die "not in a git tree" 111 | cmd=do_add 112 | only_clean_git=1;; 113 | -s|--set) setto=$2; shift; cmd=do_set;; 114 | -t|--test) cmd=do_nothing;; 115 | -f|--force) force=1;; 116 | -q|--quiet) quiet=1;; # noop 117 | -h|--help) usage; exit;; 118 | --) shift; break;; 119 | *) exit 1;; # getopt error 120 | esac 121 | shift 122 | done 123 | if [ $# -eq 0 ]; then 124 | usage >&2 125 | exit 2 126 | fi 127 | 128 | # normalize $@ into paths to APKBUILDs 129 | [ "$(echo "$@" | wc -l)" -eq 1 ] || die "can't handle paths with embedded newlines" 130 | args=$(for a; do p=$(any_buildscript "$a") || die "can't find APKBUILD for $a"; echo "$p"; done) 131 | [ $? -eq 0 ] || exit 1 132 | oldifs=$IFS 133 | IFS=$'\n' 134 | set -- $args 135 | IFS=$oldifs 136 | 137 | do_verify "$@" || exit 1 138 | $cmd "$@" 139 | -------------------------------------------------------------------------------- /bootchartd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Bootchart logger script 4 | # Ziga Mahkovec 5 | # 6 | # Modified heavily for Alpine Linux bootcharting 7 | # Timo Teras 8 | # 9 | # This script is used for data collection for the bootchart 10 | # boot performance visualization tool (http://www.bootchart.org). 11 | # 12 | # This script is tied to Alpine Init scripts and charts the 13 | # bootup procedure only. 14 | # 15 | 16 | PATH="/sbin:/bin:/usr/sbin:/usr/bin:$PATH" 17 | 18 | # Configuration for bootchartd, the bootchart logger script. 19 | TMPFS_SIZE=32m 20 | SAMPLE_PERIOD=0.2 21 | PROCESS_ACCOUNTING="yes" 22 | BOOTLOG_DEST=/var/log/bootchart.tgz 23 | LOGDIR=/bootchart 24 | EXIT_PROC="mingetty agetty rungetty getty fgetty" 25 | 26 | # Monitoring commands 27 | log_cmd_1="cat /proc/stat" 28 | log_target_1=proc_stat.log 29 | 30 | # /proc/diskstats is available in 2.6 kernels 31 | log_cmd_2="cat /proc/diskstats" 32 | log_target_2=proc_diskstats.log 33 | 34 | log_cmd_3="cat /proc/[1-9]*/stat 2>/dev/null" 35 | log_target_3=proc_ps.log 36 | 37 | # Uncomment this line for diskless stations 38 | #log_cmd_4="cat /proc/net/dev" 39 | #log_target_4=proc_netdev.log 40 | 41 | max_log=3 42 | 43 | do_logging() 44 | { 45 | # Enable process accounting if configured 46 | if [ "$PROCESS_ACCOUNTING" = "yes" ]; then 47 | [ -e kernel_pacct ] || : > kernel_pacct 48 | accton kernel_pacct 49 | fi 50 | 51 | # open file descriptors 52 | i=1 53 | while [ $i -le $max_log ]; do 54 | eval target=\"\$log_target_$i\" 55 | if [ -z "$target" ]; then 56 | max_log=$i 57 | break 58 | fi 59 | 60 | fd=$((2 + $i)) 61 | eval exec $fd'>>$target' 62 | eval log_fd_$i=$fd 63 | i=$(($i + 1)) 64 | done 65 | 66 | not_stop_logging=true 67 | while $not_stop_logging && \ 68 | { ! pidof $EXIT_PROC >/dev/null; }; do 69 | if [ -r /proc/uptime ]; then 70 | # Write the time (in jiffies). 71 | read uptime < /proc/uptime 72 | uptime=${uptime%% [0-9]*} 73 | uptime=${uptime%.*}${uptime#*.} 74 | 75 | i=1 76 | while [ $i -le $max_log ]; do 77 | eval fd=\$log_fd_$i\; cmd=\$log_cmd_$i 78 | 79 | { 80 | echo $uptime 81 | # Log the command output 82 | eval $cmd 83 | echo 84 | } >&$fd 85 | i=$(($i + 1)) 86 | done 87 | fi 88 | 89 | sleep $SAMPLE_PERIOD 90 | done 91 | 92 | # close file descriptors 93 | i=1 94 | while [ $i -le $max_log ]; do 95 | eval fd=\$log_fd_$i 96 | eval exec $fd'>&-' 97 | i=$(($i + 1)) 98 | done 99 | 100 | [ -e kernel_pacct ] && accton 101 | } 102 | 103 | # Stop the boot logger. The lock file is removed to force the loggers in 104 | # background to exit. Some final log files are created and then all log files 105 | # from the tmpfs are packaged and stored in $BOOTLOG_DEST. 106 | finalize() 107 | { 108 | # Stop process accounting if configured 109 | local pacct= 110 | [ -e kernel_pacct ] && pacct=kernel_pacct 111 | 112 | # Write system information 113 | # Log some basic information about the system. 114 | ( 115 | echo "version = $VERSION" 116 | echo "title = Boot chart for $( hostname | sed q ) ($( date ))" 117 | echo "system.uname = $( uname -srvm | sed q )" 118 | if [ -f /etc/alpine-release ]; then 119 | echo "system.release = $( sed q /etc/alpine-release )" 120 | elif [ -f /etc/gentoo-release ]; then 121 | echo "system.release = $( sed q /etc/gentoo-release )" 122 | elif [ -f /etc/SuSE-release ]; then 123 | echo "system.release = $( sed q /etc/SuSE-release )" 124 | elif [ -f /etc/debian_version ]; then 125 | echo "system.release = Debian GNU/$( uname -s ) $( cat /etc/debian_version )" 126 | elif [ -f /etc/frugalware-release ]; then 127 | echo "system.release = $( sed q /etc/frugalware-release )" 128 | elif [ -f /etc/pardus-release ]; then 129 | echo "system.release = $( sed q /etc/pardus-release )" 130 | else 131 | echo "system.release = $( sed 's/\\.//g;q' /etc/issue )" 132 | fi 133 | 134 | # Get CPU count 135 | cpucount=$(grep -c '^processor' /proc/cpuinfo || [ $? -eq 1 ]) 136 | if [ $cpucount -gt 1 -a -n "$(grep 'sibling.*2' /proc/cpuinfo)" ]; then 137 | # Hyper-Threading enabled 138 | cpucount=$(( $cpucount / 2 )) 139 | fi 140 | if grep -q '^model name' /proc/cpuinfo; then 141 | echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q )"\ 142 | "($cpucount)" 143 | else 144 | echo "system.cpu = $( grep '^cpu' /proc/cpuinfo | sed q )"\ 145 | "($cpucount)" 146 | fi 147 | 148 | echo "system.kernel.options = $( sed q /proc/cmdline )" 149 | ) >> header 150 | 151 | # Package log files 152 | tar -zcf "$BOOTLOG_DEST" header $pacct *.log 153 | rm "$LOGDIR"/* 154 | rmdir "$LOGDIR" 155 | } 156 | 157 | case "$1" in 158 | start-initfs) 159 | NEWROOT="$2" 160 | ( 161 | cleanup=true 162 | trap "not_stop_logging=false" USR1 163 | trap "cleanup=false; not_stop_logging=false" USR2 164 | 165 | mkdir "$LOGDIR" 166 | cd "$LOGDIR" 167 | do_logging 168 | if $cleanup; then 169 | sleep $SAMPLE_PERIOD 170 | finalize 171 | fi 172 | ) & 173 | echo $! > $LOGDIR/bootchart.pid 174 | ;; 175 | stop-initfs) 176 | NEWROOT="$2" 177 | 178 | cd "$LOGDIR" 179 | mkdir "$NEWROOT$LOGDIR" 180 | cp /sbin/bootchartd $NEWROOT/sbin 181 | PID=$(cat bootchart.pid) 182 | kill -USR2 $PID 183 | wait $PID 184 | mv * "$NEWROOT$LOGDIR" 185 | ;; 186 | start-rootfs) 187 | ( 188 | trap "not_stop_logging=false" USR1 189 | cd "$LOGDIR" 190 | do_logging 191 | finalize 192 | ) & 193 | shift 194 | exec "$@" 195 | ;; 196 | esac 197 | 198 | exit 0 199 | -------------------------------------------------------------------------------- /buildlab.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | program_version=@VERSION@ 4 | sysconfdir=@sysconfdir@ 5 | abuildrepo=/var/lib/buildlab/result 6 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 7 | 8 | BUILD_BASE="build-base" 9 | SUDO=${SUDO:-"sudo"} 10 | FAKEROOT=${FAKEROOT:-"fakeroot"} 11 | APK=${APK:-apk} 12 | 13 | # read config 14 | ABUILD_CONF=${ABUILD_CONF:-"$sysconfdir/abuild.conf"} 15 | [ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF" 16 | 17 | default_colors() { 18 | NORMAL="\033[1;0m" 19 | STRONG="\033[1;1m" 20 | RED="\033[1;31m" 21 | GREEN="\033[1;32m" 22 | YELLOW="\033[1;33m" 23 | BLUE="\033[1;34m" 24 | } 25 | 26 | default_colors 27 | 28 | is_local() { 29 | case "$1" in 30 | http://*|ftp://*|https://*|saveas-*://*) 31 | return 1;; 32 | esac 33 | return 0 34 | } 35 | 36 | msg() { 37 | local prompt="$GREEN>>>${NORMAL}" 38 | [ -z "$quiet" ] && printf "${prompt} $@\n" >&2 39 | } 40 | 41 | error() { 42 | local prompt="$RED>>>${NORMAL}" 43 | printf "${prompt} $@\n" >&2 44 | } 45 | 46 | die() { 47 | error "$@" 48 | exit 1 49 | } 50 | 51 | runpart() { 52 | local part=$1 53 | msg "Running part $part" 54 | $part || die "$part failed" 55 | } 56 | 57 | is_vserver() { 58 | grep -E -q '^VxID:[[:space:]]*[0-9]+' /proc/self/status 59 | } 60 | 61 | do_chroot_open() { 62 | local path="$1" 63 | if is_vserver; then 64 | # vserver does not allow us mount or create devices 65 | # but we can create hard links as long as chroot is 66 | # on same filesystem as real root 67 | rmdir "$path"/proc "$path"/sys "$path"/dev 2>/dev/null 68 | ln /dev "$path"/dev 69 | ln /proc "$path"/proc 70 | ln /sys "$path"/sys 71 | 72 | else 73 | mkdir -p "$path"/dev "$path"/proc "$path"/sys 74 | mount -o bind /dev "$path"/dev || return 1 75 | mount -o bind /proc "$path"/proc 76 | mount -o bind /sys "$path"/sys 77 | fi 78 | } 79 | 80 | do_chroot_close() { 81 | local path="$1" 82 | if is_vserver; then 83 | rmdir "$path"/dev "$path"/proc "$path"/sys 84 | else 85 | umount "$path"/dev "$path"/proc "$path"/sys 86 | fi 87 | } 88 | 89 | do_chroot_action() { 90 | local path="$1" 91 | local command="$2" 92 | 93 | msg "Doing chroot action '$command' in '$path'..." 94 | 95 | do_chroot_open "$path" || return 1 96 | shift; 97 | 98 | # XXX: we have to do this because busybox clobbers us, bleah. 99 | echo $* > "$path"/.chroot-action.sh 100 | chroot "$path" /bin/sh /.chroot-action.sh 101 | rm "$path"/.chroot-action.sh 102 | 103 | do_chroot_close 104 | } 105 | 106 | update_chroot() { 107 | local path="$1" 108 | 109 | apk --root $path --repositories "$path"/etc/apk/repositories update 110 | apk --root $path --repositories "$path"/etc/apk/repositories upgrade -a 111 | } 112 | 113 | prepare_chroot() { 114 | local path="$1" 115 | local version="$2" 116 | local mirror="$3" 117 | local arch="$4" 118 | local enablecache="$5" 119 | 120 | msg "Setting up repositories for mirror $mirror with version $version at $path..." 121 | 122 | mkdir -p "$path"/etc/apk 123 | echo "http://$mirror/alpine/$version/main" >> "$path"/etc/apk/repositories 124 | echo "http://$mirror/alpine/$version/testing" >> "$path"/etc/apk/repositories 125 | 126 | if [ ! -z "$enablecache" ]; then 127 | mkdir -p "$path"/var/cache/apk 128 | ln -s /var/cache/apk "$path"/etc/apk/cache 129 | fi 130 | 131 | echo "alpine-base" > "$path"/etc/apk/world 132 | mkdir -p "$path"/lib/apk/db 133 | mkdir -p "$path"/var/lock 134 | mkdir -p "$path"/var/cache/apk 135 | mkdir -p "$path"/tmp 136 | 137 | mkdir -p "$path"/etc 138 | cp /etc/resolv.conf "$path"/etc/resolv.conf 139 | 140 | msg "Updating package lists..." 141 | 142 | apk --arch $buildarch --root $path --repositories "$path"/etc/apk/repositories update 143 | 144 | msg "Installing alpine-base..." 145 | 146 | apk --arch $buildarch --root $path --repositories "$path"/etc/apk/repositories add --initdb alpine-base 147 | 148 | msg "Installing abuild..." 149 | 150 | apk --arch $buildarch --root $path --repositories "$path"/etc/apk/repositories add --initdb abuild 151 | 152 | msg "Installing build-base..." 153 | 154 | apk --arch $buildarch --root $path --repositories "$path"/etc/apk/repositories add --initdb build-base 155 | 156 | msg "Adding abuild user..." 157 | 158 | do_chroot_action "$path" adduser -D -G abuild abuild 159 | echo "abuild ALL=NOPASSWD: ALL" >> "$path"/etc/sudoers 160 | chmod 440 "$path"/etc/sudoers 161 | 162 | msg "Generating buildlab signing keys..." 163 | do_chroot_action "$path" su abuild -c "'abuild-keygen -ai'" 164 | 165 | msg "Setting up repository symlink..." 166 | mkdir -p "$path"/home/abuild/.cache/apks 167 | do_chroot_action "$path" chown abuild:abuild /home/abuild/${src} 168 | do_chroot_action "$path" ln -sf .cache/apks /home/abuild/repo 169 | 170 | msg "Build chroot is ready!" 171 | } 172 | 173 | build_package() { 174 | local path="$1" 175 | local apkbuild="$2" 176 | srcdir="$(dirname $apkbuild)" 177 | 178 | msg "Parsing $apkbuild..." 179 | . "$apkbuild" 180 | 181 | msg "Copying local sources..." 182 | 183 | mkdir -p "$path"/home/abuild/src 184 | chmod 666 "$path"/home/abuild/src 185 | 186 | for src in $source $install; do 187 | is_local $src || continue 188 | 189 | msg "${srcdir}/${src} -> ${path}/home/abuild/src/${src} ..." 190 | cp ${srcdir}/${src} "${path}"/home/abuild/${src} 191 | do_chroot_action "$path" chown abuild:abuild /home/abuild/${src} 192 | done 193 | 194 | for i in $triggers; do 195 | src=${i%=*} 196 | is_local $src || continue 197 | 198 | msg "${srcdir}/${src} -> ${path}/home/abuild/src/${src} ..." 199 | cp ${srcdir}/${src} "${path}"/home/abuild/${src} 200 | do_chroot_action "$path" chown abuild:abuild /home/abuild/${src} 201 | done 202 | 203 | cp $apkbuild "$path"/home/abuild 204 | do_chroot_action "$path" chown abuild:abuild /home/abuild/$(basename $apkbuild) 205 | 206 | msg "Invoking abuild..." 207 | do_chroot_action "$path" su abuild -c "'cd /home/abuild; abuild -r'" 208 | 209 | msg "Copying back results to ${abuildrepo}..." 210 | mkdir -p ${abuildrepo} 211 | for papk in "${path}"/home/abuild/*.apk; do 212 | apk=$(basename $papk) 213 | msg "$papk -> ${abuildrepo}/${apk}" 214 | cp $papk ${abuildrepo}/${apk} 215 | done 216 | 217 | msg "Cleaning up..." 218 | rm -rf "$path"/home/abuild/src 219 | rm -rf "$path"/home/abuild/pkg 220 | rm -f "$path"/home/abuild/APKBUILD 221 | } 222 | 223 | usage() { 224 | cat <<-EOF 225 | buildlab $program_version 226 | 227 | Common options: 228 | 229 | -q Quiet operation 230 | -p Path to buildroot 231 | 232 | Creating build roots (buildlab -C): 233 | 234 | -m APK repository mirror 235 | -v APK distribution version 236 | -a APK repository architecture 237 | -k Enable APK caching 238 | 239 | Updating build roots (buildlab -u): 240 | 241 | No special options. 242 | 243 | Building packages (buildlab -b): 244 | 245 | -b APKBUILD file 246 | 247 | Examples: 248 | 249 | sudo ./buildlab -C -p /home/nenolod/buildroot -m dl-3.alpinelinux.org -v edge -a x86_64 250 | sudo ./buildlab -b /home/nenolod/aports/main/gnome-panel/APKBUILD -p /home/nenolod/buildroot 251 | sudo ./buildlab -u -p /home/nenolod/buildroot 252 | EOF 253 | } 254 | 255 | unset force 256 | unset recursive 257 | while getopts "chqCkp:v:m:a:b:u" opt; do 258 | case $opt in 259 | 'c') default_colors 260 | color_opt="-c";; 261 | 'h') usage;; 262 | 'q') quiet="-q";; 263 | 'C') create="-c";; 264 | 'p') buildpath="$OPTARG";; 265 | 'm') buildmirror="$OPTARG";; 266 | 'v') buildver="$OPTARG";; 267 | 'a') buildarch="$OPTARG";; 268 | 'k') enablecache=1;; 269 | 'b') buildpkg="$OPTARG";; 270 | 'u') update="-u";; 271 | esac 272 | done 273 | shift $(( $OPTIND - 1 )) 274 | 275 | if [ ! -z "$create" ]; then 276 | msg "Creating new chroot at $buildpath..." 277 | prepare_chroot $buildpath $buildver $buildmirror $buildarch $enablecache 278 | exit 0 279 | fi 280 | 281 | if [ ! -z "$buildpkg" ]; then 282 | msg "Building APKBUILD $buildpkg in chroot $buildpath..." 283 | build_package $buildpath $buildpkg 284 | exit 0 285 | fi 286 | 287 | if [ ! -z "$update" ]; then 288 | msg "Updating chroot at $buildpath..." 289 | update_chroot $buildpath 290 | exit 0 291 | fi 292 | -------------------------------------------------------------------------------- /checkapk.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # checkapk - find ABI breakages in package upgrades 4 | # Copyright (c) 2012 Natanael Copa 5 | # 6 | # Distributed under GPL-2.0-only 7 | # 8 | 9 | program_version=@VERSION@ 10 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 11 | 12 | if ! [ -f "$sharedir/functions.sh" ]; then 13 | echo "$sharedir/functions.sh: not found" >&2 14 | exit 1 15 | fi 16 | . "$sharedir/functions.sh" 17 | 18 | 19 | usage() { 20 | cat <<-__EOF__ 21 | $program $program_version - find ABI breakages in package upgrades 22 | Usage: $program [-h|--help] 23 | 24 | Run in the directory of a built package. 25 | 26 | Options: 27 | -h, --help Print this help 28 | 29 | __EOF__ 30 | } 31 | 32 | args=$(getopt -o h --long help \ 33 | -n "$program" -- "$@") 34 | 35 | if [ $? -ne 0 ]; then 36 | usage >&2 37 | exit 2 38 | fi 39 | eval set -- "$args" 40 | while true; do 41 | case $1 in 42 | -h|--help) usage; exit 0;; 43 | --) shift; break;; 44 | *) exit 1;; # getopt error 45 | esac 46 | shift 47 | done 48 | 49 | if [ $# -gt 0 ]; then 50 | usage >&2 51 | exit 2 52 | fi 53 | 54 | if ! [ -f "$ABUILD_CONF" ] && ! [ -f "$ABUILD_USERCONF" ] && ! [ -f "$ABUILD_DEFCONF" ]; then 55 | die "no abuild.conf found" 56 | fi 57 | 58 | if ! [ -f APKBUILD ]; then 59 | die 'must be run in the directory of a built package' 60 | fi 61 | 62 | if ! [ -n "$CARCH" ]; then 63 | die "failed to detect CARCH" 64 | fi 65 | 66 | . ./APKBUILD 67 | 68 | startdir="$PWD" 69 | tmpdir=$(mktemp -d -t checkpkg-script.XXXXXX) 70 | trap "rm -rf '$tmpdir'; exit" INT EXIT 71 | cd "$tmpdir" || die "failed to create temp dir" 72 | 73 | # storage for downloaded/copied apks 74 | mkdir -p apks 75 | 76 | # default to pigz for unpacking 77 | gunzip="$(command -v pigz || echo gzip) -d" 78 | 79 | for i in $pkgname $subpackages; do 80 | _pkgname=${i%%:*} 81 | pkg=${_pkgname}-$pkgver-r$pkgrel 82 | pkgfile=${pkg}.apk 83 | repodir=${startdir%/*} 84 | repo=${repodir##*/} 85 | 86 | for filepath in "$PKGDEST"/$pkgfile "$REPODEST"/$repo/$CARCH/$pkgfile "$startdir"/$pkgfile; do 87 | if [ -f "$filepath" ]; then 88 | break 89 | fi 90 | done 91 | [ -f "$filepath" ] || die "can't find $pkgfile" 92 | 93 | # generate a temp repositories file with only the http(s) repos 94 | grep -E "^https?:" /etc/apk/repositories > "$tmpdir"/repositories 95 | 96 | oldpkg=$(apk fetch --repositories-file "$tmpdir"/repositories --simulate $_pkgname 2>&1 | sed 's/^Downloading //') 97 | if [ "${oldpkg}" = "${pkg}" ]; then 98 | die "the built package ($_pkgname) is already in the repo" 99 | fi 100 | 101 | # apk info could return multiple lines if multiple packages share a provide 102 | # (e.g. dnsmasq); filter with the exact package name and take the second line: 103 | # 7zip-23.01-r0 installed size: 104 | # 1668 KiB 105 | newsize="$(apk info --repositories-file /dev/null --repository "$REPODEST"/$repo --size $_pkgname | \ 106 | grep -F "$pkg" -A1 | \ 107 | tail -n1)" 108 | oldsize="$(apk info --repositories-file "$tmpdir"/repositories --size "$_pkgname" | \ 109 | grep -F "$oldpkg" -A1 | \ 110 | tail -n1)" 111 | 112 | if [ "$oldsize" = "$newsize" ]; then 113 | msg "No size differences for $_pkgname." 114 | else 115 | msg "Size difference for $_pkgname: $oldsize -> $newsize" 116 | fi 117 | 118 | apk fetch --quiet --repositories-file "$tmpdir"/repositories --stdout "$_pkgname" > apks/old.apk \ 119 | || msg2 "Old apk for $_pkgname missing. (new package/arch? broken internet?)" 120 | 121 | # pre-uncompress to not decompress twice 122 | # we do a decompression + tar -t for the file list, but then later we might do a full extraction for sodiff. 123 | # to not decompress here and then later again, store the intermediate tar 124 | $gunzip -c 2>/dev/null < apks/old.apk > apks/old.tar & 125 | $gunzip -c "$filepath" < "$filepath" > apks/new.tar & 126 | wait 127 | tar -t -f apks/old.tar 2>/dev/null | grep -v '^\.SIGN\.' | sort > "filelist-$_pkgname-old" & 128 | tar -t -f apks/new.tar | grep -v '^\.SIGN\.' | sort > "filelist-$_pkgname-new" & 129 | wait 130 | 131 | diff -U3 "filelist-$_pkgname-old" "filelist-$_pkgname-new" 132 | 133 | if diff -U0 "filelist-$_pkgname-old" "filelist-$_pkgname-new" | grep -q '\.so'; then 134 | echo "SODIFF:" 135 | 136 | mkdir -p "$_pkgname-pkg-old" "$_pkgname-pkg-new" 137 | tar -C "$_pkgname-pkg-old" 2>/dev/null -x -f apks/old.tar > /dev/null & 138 | tar -C "$_pkgname-pkg-new" -x -f apks/new.tar > /dev/null & 139 | wait 140 | 141 | # filter to things that start with -+ but strip the header (---/+++) 142 | diff -U0 "filelist-$_pkgname-old" "filelist-$_pkgname-new" | grep -E '^(\+|-)[A-Za-z0-9]+' | grep '\.so' | while read -r diff_sofile; do 143 | case "$diff_sofile" in 144 | -*) path="$_pkgname-pkg-old"; sofile="${diff_sofile#\-}" ;; 145 | +*) path="$_pkgname-pkg-new"; sofile="${diff_sofile#\+}" ;; 146 | esac 147 | 148 | # skip symlinks (only adds duplicate output or is dangling), and things that aren't valid elfs 149 | # matching .so above matches anything with .so in the name, e.g. xyz.sourceforge 150 | if ! [ -L "$path"/"$sofile" ] && readelf -h "$path"/"$sofile" >/dev/null 2>&1; then 151 | echo "$diff_sofile: " "$(objdump -p "$path"/"$sofile" | grep SONAME)" 152 | fi 153 | done 154 | else 155 | msg "No soname differences for $_pkgname." 156 | fi 157 | done 158 | -------------------------------------------------------------------------------- /default.conf: -------------------------------------------------------------------------------- 1 | export CFLAGS="-Os -fstack-clash-protection -Wformat -Werror=format-security" 2 | export CXXFLAGS="-Os -fstack-clash-protection -Wformat -Werror=format-security" 3 | export CXXFLAGS="$CXXFLAGS -D_GLIBCXX_ASSERTIONS=1 -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS=1 -D_LIBCPP_ENABLE_HARDENED_MODE=1" 4 | export LDFLAGS="-Wl,--as-needed,-O1,--sort-common" 5 | export GOFLAGS="-buildmode=pie -modcacherw -trimpath -buildvcs=false" 6 | # Do note that these should work with at least GDC and LDC 7 | export DFLAGS="-Os" 8 | 9 | export JOBS=$(nproc) 10 | export MAKEFLAGS=-j$JOBS 11 | export SAMUFLAGS=-j$JOBS 12 | export CARGO_BUILD_JOBS=$JOBS 13 | export CMAKE_BUILD_PARALLEL_LEVEL=$JOBS 14 | export CTEST_PARALLEL_LEVEL=$JOBS 15 | 16 | export CARGO_PROFILE_RELEASE_OPT_LEVEL="s" 17 | export CARGO_PROFILE_RELEASE_PANIC="abort" 18 | export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 19 | export CARGO_PROFILE_RELEASE_LTO="true" 20 | 21 | export CTEST_OUTPUT_ON_FAILURE=ON 22 | export CTEST_NO_TESTS_ACTION=error 23 | 24 | export PERL_MM_USE_DEFAULT=1 25 | 26 | SRCDEST=/var/cache/distfiles 27 | 28 | # The package will be stored as $REPODEST/$repo/$arch/$pkgname-$pkgver-r$pkgrel.apk 29 | # where $repo is the name of the parent directory of $startdir. 30 | REPODEST=$HOME/packages/ 31 | 32 | # what to clean up after a successful build 33 | CLEANUP="srcdir bldroot pkgdir deps" 34 | 35 | # what to cleanup after a failed build 36 | ERROR_CLEANUP="bldroot deps" 37 | -------------------------------------------------------------------------------- /functions.sh.in: -------------------------------------------------------------------------------- 1 | # /usr/share/abuild/functions.sh 2 | 3 | sysconfdir=@sysconfdir@ 4 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 5 | program=${0##*/} 6 | 7 | arch_to_hostspec() { 8 | case "$1" in 9 | aarch64) echo "aarch64-alpine-linux-musl" ;; 10 | armel) echo "armv5-alpine-linux-musleabi" ;; 11 | armhf) echo "armv6-alpine-linux-musleabihf" ;; 12 | armv7) echo "armv7-alpine-linux-musleabihf" ;; 13 | loongarch32) echo "loongarch32-alpine-linux-musl" ;; 14 | loongarchx32) echo "loongarchx32-alpine-linux-musl" ;; 15 | loongarch64) echo "loongarch64-alpine-linux-musl" ;; 16 | mips) echo "mips-alpine-linux-musl" ;; 17 | mips64) echo "mips64-alpine-linux-musl" ;; 18 | mipsel) echo "mipsel-alpine-linux-musl" ;; 19 | mips64el) echo "mips64el-alpine-linux-musl" ;; 20 | ppc) echo "powerpc-alpine-linux-musl" ;; 21 | ppc64) echo "powerpc64-alpine-linux-musl" ;; 22 | ppc64le) echo "powerpc64le-alpine-linux-musl" ;; 23 | riscv32) echo "riscv32-alpine-linux-musl" ;; 24 | riscv64) echo "riscv64-alpine-linux-musl" ;; 25 | s390x) echo "s390x-alpine-linux-musl" ;; 26 | sh2eb) echo "sh2eb-alpine-linux-muslfdpic" ;; 27 | sh3) echo "sh3-alpine-linux-musl" ;; 28 | sh4) echo "sh4-alpine-linux-musl" ;; 29 | x86) echo "i586-alpine-linux-musl" ;; 30 | x86_64) echo "x86_64-alpine-linux-musl" ;; 31 | *) echo "unknown" ;; 32 | esac 33 | } 34 | 35 | hostspec_to_arch() { 36 | case "$1" in 37 | aarch64*-*-*-*) echo "aarch64" ;; 38 | arm*-*-*-*eabi) echo "armel" ;; 39 | armv6*-*-*-*eabihf) echo "armhf" ;; 40 | armv7*-*-*-*eabihf) echo "armv7" ;; 41 | i[0-9]86-*-*-*) echo "x86" ;; 42 | loongarch32-*-*-*) echo "loongarch32" ;; 43 | loongarchx32-*-*-*) echo "loongarchx32" ;; 44 | loongarch64-*-*-*) echo "loongarch64" ;; 45 | mips-*-*-*) echo "mips" ;; 46 | mips64-*-*-*) echo "mips64" ;; 47 | mipsel-*-*-*) echo "mipsel" ;; 48 | mips64el-*-*-*) echo "mips64el" ;; 49 | powerpc-*-*-*) echo "ppc" ;; 50 | powerpc64-*-*-*) echo "ppc64" ;; 51 | powerpc64le-*-*-*) echo "ppc64le" ;; 52 | riscv32-*-*-*) echo "riscv32" ;; 53 | riscv64-*-*-*) echo "riscv64" ;; 54 | s390x-*-*-*) echo "s390x" ;; 55 | sh2eb-*-*-*) echo "sh2eb" ;; 56 | sh3-*-*-*) echo "sh3" ;; 57 | sh4-*-*-*) echo "sh4" ;; 58 | x86_64-*-*-*) echo "x86_64" ;; 59 | *) echo "unknown" ;; 60 | esac 61 | } 62 | 63 | hostspec_to_libc() { 64 | case "$1" in 65 | *-*-*-uclibc*) echo "uclibc" ;; 66 | *-*-*-musl*) echo "musl" ;; 67 | *-*-*-gnu*) echo "glibc" ;; 68 | *) echo "unknown" ;; 69 | esac 70 | } 71 | 72 | readconfig() { 73 | local _APORTSDIR _BUILDDIR _PKGDEST _SRCPKGDEST _REPODEST _SRCDEST _ABUILD_USERDIR 74 | local _CC=cc _CXX=c++ _LD=ld _CARCH _CHOST _CTARGET _CPPFLAGS _CFLAGS _CXXFLAGS _LDFLAGS 75 | local _JOBS _MAKEFLAGS _PACKAGER _USE_COLORS _USE_CCACHE 76 | local _BUILDCC _BUILDCXX _BUILDLD _BUILDCPPFLAGS _BUILDCXXFLAGS _BUILDCFLAGS 77 | local _BUILDLDFLAGS 78 | local gitbase= 79 | [ -n "${APORTSDIR+x}" ] && _APORTSDIR=$APORTSDIR 80 | [ -n "${BUILDDIR+x}" ] && _BUILDDIR=$BUILDDIR 81 | [ -n "${PKGDEST+x}" ] && _PKGDEST=$PKGDEST 82 | [ -n "${SRCPKGDEST+x}" ] && _SRCPKGDEST=$SRCPKGDEST 83 | [ -n "${REPODEST+x}" ] && _REPODEST=$REPODEST 84 | [ -n "${SRCDEST+x}" ] && _SRCDEST=$SRCDEST 85 | [ -n "${ABUILD_USERDIR+x}" ] && _ABUILD_USERDIR=$ABUILD_USERDIR 86 | [ -n "${CC+x}" ] && _CC=$CC 87 | [ -n "${CXX+x}" ] && _CXX=$CXX 88 | [ -n "${LD+x}" ] && _LD=$LD 89 | [ -n "${CARCH+x}" ] && _CARCH=$CARCH 90 | [ -n "${CHOST+x}" ] && _CHOST=$CHOST 91 | [ -n "${CTARGET+x}" ] && _CTARGET=$CTARGET 92 | [ -n "${CPPFLAGS+x}" ] && _CPPFLAGS=$CPPFLAGS 93 | [ -n "${CFLAGS+x}" ] && _CFLAGS=$CFLAGS 94 | [ -n "${CXXFLAGS+x}" ] && _CXXFLAGS=$CXXFLAGS 95 | [ -n "${LDFLAGS+x}" ] && _LDFLAGS=$LDFLAGS 96 | [ -n "${BUILDCC+x}" ] && _BUILDCC=$BUILDCC 97 | [ -n "${BUILDCXX+x}" ] && _BUILDCXX=$BUILDCXX 98 | [ -n "${BUILDCPPFLAGS+x}" ] && _BUILDCPPFLAGS=$BUILDCPPFLAGS 99 | [ -n "${BUILDCXXFLAGS+x}" ] && _BUILDCXXFLAGS=$BUILDCXXFLAGS 100 | [ -n "${BUILDCFLAGS+x}" ] && _BUILDCFLAGS=$BUILDCFLAGS 101 | [ -n "${BUILDLDFLAGS+x}" ] && _BUILDLDFLAGS=$BUILDLDFLAGS 102 | [ -n "${JOBS+x}" ] && _JOBS=$JOBS 103 | [ -n "${MAKEFLAGS+x}" ] && _MAKEFLAGS=$MAKEFLAGS 104 | [ -n "${PACKAGER+x}" ] && _PACKAGER=$PACKAGER 105 | [ -n "${USE_COLORS+x}" ] && _USE_COLORS="$USE_COLORS" 106 | [ -n "${USE_CCACHE+x}" ] && _USE_CCACHE="$USE_CCACHE" 107 | : ${ABUILD_DEFCONF:=$sharedir/default.conf} 108 | [ -f "$ABUILD_DEFCONF" ] && . "$ABUILD_DEFCONF" 109 | : ${ABUILD_CONF:=$sysconfdir/abuild.conf} 110 | [ -f "$ABUILD_CONF" ] && . "$ABUILD_CONF" 111 | ABUILD_USERDIR=${_ABUILD_USERDIR-${ABUILD_USERDIR:-$HOME/.abuild}} 112 | : ${ABUILD_USERCONF:=$ABUILD_USERDIR/abuild.conf} 113 | [ -f "$ABUILD_USERCONF" ] && . "$ABUILD_USERCONF" 114 | APORTSDIR=${_APORTSDIR-$APORTSDIR} 115 | 116 | : ${GIT:=git} 117 | gitbase=$($GIT rev-parse --show-toplevel 2>/dev/null) || true # already is -P 118 | if [ -d "$APORTSDIR" ]; then 119 | APORTSDIR=$(cd "$APORTSDIR"; pwd -P) 120 | elif [ -z "$APORTSDIR" ] && [ -d "$HOME/aports" ]; then 121 | APORTSDIR=$(cd "$HOME/aports"; pwd -P) 122 | else 123 | if [ -n "$gitbase" ]; then 124 | case $($GIT remote get-url origin 2>/dev/null || true) in 125 | # '.git' for SSH URLs, and no suffix for HTTPS URLs 126 | */aports|*/aports.git) APORTSDIR=$gitbase ;; 127 | *) APORTSDIR= ;; 128 | esac 129 | else 130 | APORTSDIR= 131 | fi 132 | fi 133 | # source any .abuild file at the aports root, but only if we are currently in aports tree 134 | [ -n "$APORTSDIR" ] && [ -f "$APORTSDIR/.abuild" ] && [ "$APORTSDIR" = "$gitbase" ] && . "$APORTSDIR/.abuild" 135 | BUILDDIR=${_BUILDDIR-$BUILDDIR} 136 | PKGDEST=${_PKGDEST-$PKGDEST} 137 | SRCPKGDEST=${_SRCPKGDEST-$SRCPKGDEST} 138 | REPODEST=${_REPODEST-$REPODEST} 139 | SRCDEST=${_SRCDEST-$SRCDEST} 140 | CC=${_CC-$CC} 141 | CXX=${_CXX-$CXX} 142 | LD=${_LD-$LD} 143 | CARCH=${_CARCH-$CARCH} 144 | CHOST=${_CHOST-$CHOST} 145 | CTARGET=${_CTARGET-$CTARGET} 146 | CPPFLAGS=${_CPPFLAGS-$CPPFLAGS} 147 | CFLAGS=${_CFLAGS-$CFLAGS} 148 | CXXFLAGS=${_CXXFLAGS-$CXXFLAGS} 149 | LDFLAGS=${_LDFLAGS-$LDFLAGS} 150 | BUILDCC=${_BUILDCC-$BUILDCC} 151 | BUILDCXX=${_BUILDCXX-$BUILDCXX} 152 | BUILDLD=${_BUILDLD-$BUILDLD} 153 | BUILDCPPFLAGS=${_BUILDCPPFLAGS-$BUILDCPPFLAGS} 154 | BUILDCXXFLAGS=${_BUILDCXXFLAGS-$BUILDCXXFLAGS} 155 | BUILDCFLAGS=${_BUILDCFLAGS-$BUILDCFLAGS} 156 | BUILDLDFLAGS=${_BUILDLDFLAGS-$BUILDLDFLAGS} 157 | JOBS=${_JOBS-$JOBS} 158 | MAKEFLAGS=${_MAKEFLAGS-$MAKEFLAGS} 159 | PACKAGER=${_PACKAGER-$PACKAGER} 160 | USE_COLORS=${_USE_COLORS-$USE_COLORS} 161 | USE_CCACHE=${_USE_CCACHE-$USE_CCACHE} 162 | 163 | # export BUILD variables because it is used as variables specific to the platform running the compiler 164 | # instead of the platform the compiled binaries are supposed to run on 165 | export BUILDCC="$CC" 166 | export BUILDCXX="$CXX" 167 | export BUILDLD="$LD" 168 | export BUILDCPPFLAGS="$CPPFLAGS" 169 | export BUILDCXXFLAGS="$CXXFLAGS" 170 | export BUILDCFLAGS="$CFLAGS" 171 | export BUILDLDFLAGS="$LDFLAGS" 172 | 173 | [ -z "$CBUILD" ] && CBUILD="$(${APK:-apk} --print-arch 2>/dev/null || :)" 174 | [ -z "$CHOST" ] && CHOST="$CBUILD" 175 | [ -z "$CTARGET" ] && CTARGET="$CHOST" 176 | [ "$(arch_to_hostspec $CBUILD)" != "unknown" ] && CBUILD="$(arch_to_hostspec $CBUILD)" 177 | [ "$(arch_to_hostspec $CHOST)" != "unknown" ] && CHOST="$(arch_to_hostspec $CHOST)" 178 | [ "$(arch_to_hostspec $CTARGET)" != "unknown" ] && CTARGET="$(arch_to_hostspec $CTARGET)" 179 | if [ -z "$CBUILD" ]; then 180 | echo "Unable to deduce build architecture. Install apk-tools, or set CBUILD." >&2 181 | exit 1 182 | fi 183 | 184 | [ -z "$CARCH" ] && CARCH="$(hostspec_to_arch $CHOST)" 185 | [ -z "$CLIBC" ] && CLIBC="$(hostspec_to_libc $CHOST)" 186 | [ -z "$CBUILD_ARCH" ] && CBUILD_ARCH="$(hostspec_to_arch $CBUILD)" 187 | [ -z "$CTARGET_ARCH" ] && CTARGET_ARCH="$(hostspec_to_arch $CTARGET)" 188 | [ -z "$CTARGET_LIBC" ] && CTARGET_LIBC="$(hostspec_to_libc $CTARGET)" 189 | 190 | if [ "$CHOST" != "$CTARGET" ]; then 191 | # setup environment for creating cross compiler 192 | [ -z "$CBUILDROOT" ] && export CBUILDROOT="$HOME/sysroot-$CTARGET_ARCH/" 193 | elif [ "$CBUILD" != "$CHOST" ]; then 194 | # setup build root 195 | [ -z "$CBUILDROOT" ] && export CBUILDROOT="$HOME/sysroot-$CTARGET_ARCH/" 196 | # prepare pkg-config for cross building 197 | [ -z "$PKG_CONFIG_PATH" ] && export PKG_CONFIG_PATH="${CBUILDROOT}/usr/lib/pkgconfig/:${CBUILDROOT}/usr/share/pkgconfig/" 198 | [ -z "$PKG_CONFIG_SYSROOT_DIR" ] && export PKG_CONFIG_SYSROOT_DIR="${CBUILDROOT}" 199 | # libtool bug workaround for extra rpaths 200 | [ -z "$lt_cv_sys_lib_dlsearch_path_spec" ] && \ 201 | export lt_cv_sys_lib_dlsearch_path_spec="${CBUILDROOT}/lib ${CBUILDROOT}/usr/lib /usr/lib /lib /usr/local/lib" 202 | # setup cross-compiler 203 | if [ -z "$CROSS_COMPILE" ]; then 204 | export CROSS_COMPILE="${CHOST}-" 205 | export HOSTCC="$CC" 206 | export HOSTCXX="$CXX" 207 | export HOSTLD="$LD" 208 | export HOSTCPPFLAGS="$CPPFLAGS" 209 | export HOSTCXXFLAGS="$CXXFLAGS" 210 | export HOSTCFLAGS="$CFLAGS" 211 | export HOSTLDFLAGS="$LDFLAGS" 212 | export CC=${CROSS_COMPILE}$CC 213 | export CXX=${CROSS_COMPILE}$CXX 214 | export LD=${CROSS_COMPILE}$LD 215 | export CPPFLAGS="--sysroot=${CBUILDROOT} $CPPFLAGS" 216 | export CXXFLAGS="--sysroot=${CBUILDROOT} $CXXFLAGS" 217 | export CFLAGS="--sysroot=${CBUILDROOT} $CFLAGS" 218 | export LDFLAGS="--sysroot=${CBUILDROOT} $LDFLAGS" 219 | fi 220 | fi 221 | return 0 222 | } 223 | readconfig 224 | 225 | # expects $1 to be a package directory in the aports tree ('foo' or 'main/foo') 226 | # outputs APKBUILD's path if successful 227 | aports_buildscript() { 228 | [ -n "$APORTSDIR" ] || return 1 229 | if [ "${1#*/}" != "$1" ]; then 230 | ( cd "$APORTSDIR/$1" && [ -f APKBUILD ] && echo "$PWD/APKBUILD" ) 231 | else 232 | ( cd "$APORTSDIR"/*/"$1" && [ -f APKBUILD ] && echo "$PWD/APKBUILD" ) 233 | fi 234 | } 235 | 236 | # expects $1 to be a file, or a directory containing an APKBUILD, or a package directory in the aports tree 237 | # outputs APKBUILD's path if successful (doesn't verify that it's a valid APKBUILD) 238 | any_buildscript() { 239 | if [ -f "$1" ]; then 240 | echo "$1" 241 | elif [ -d "$1" ]; then 242 | [ -f "$1/APKBUILD" ] || return 1 243 | echo "$1/APKBUILD" 244 | else 245 | aports_buildscript "$1" || return 1 246 | fi 247 | } 248 | 249 | apk_tar() { 250 | if [ -n "$SOURCE_DATE_EPOCH" ]; then 251 | set -- --mtime="@$SOURCE_DATE_EPOCH" "$@" 252 | fi 253 | tar --format=posix \ 254 | --pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0,ctime:=0 \ 255 | --no-recursion --null -f - -c "$@" 256 | } 257 | 258 | # output functions 259 | msg() { 260 | [ -n "$quiet" ] && return 0 261 | local prompt="$GREEN>>>${NORMAL}" 262 | printf "${prompt} %s\n" "$1" >&2 263 | } 264 | 265 | msg2() { 266 | [ -n "$quiet" ] && return 0 267 | # ">>> %s" 268 | printf " %s\n" "$1" >&2 269 | } 270 | 271 | warning() { 272 | local prompt="${YELLOW}>>> WARNING:${NORMAL}" 273 | printf "${prompt} %s\n" "$1" >&2 274 | } 275 | 276 | warning2() { 277 | # ">>> WARNING: %s\n" 278 | printf " %s\n" "$1" >&2 279 | } 280 | 281 | error() { 282 | local prompt="${RED}>>> ERROR:${NORMAL}" 283 | printf "${prompt} %s\n" "$1" >&2 284 | } 285 | 286 | error2() { 287 | # ">>> ERROR: 288 | printf " %s\n" "$1" >&2 289 | } 290 | 291 | set_xterm_title() { 292 | if [ "$TERM" = xterm ] && [ -n "$USE_COLORS" ]; then 293 | printf "\033]0;$1\007" >&2 294 | fi 295 | } 296 | 297 | disable_colors() { 298 | NORMAL="" 299 | STRONG="" 300 | RED="" 301 | GREEN="" 302 | YELLOW="" 303 | BLUE="" 304 | } 305 | 306 | enable_colors() { 307 | NORMAL="\033[1;0m" 308 | STRONG="\033[1;1m" 309 | RED="\033[1;31m" 310 | GREEN="\033[1;32m" 311 | YELLOW="\033[1;33m" 312 | BLUE="\033[1;34m" 313 | } 314 | 315 | if [ "$USE_COLORS" = force ]; then 316 | enable_colors 317 | elif [ -n "$USE_COLORS" ] && [ -t 1 ]; then 318 | enable_colors 319 | else 320 | disable_colors 321 | fi 322 | 323 | # caller may override 324 | cleanup() { 325 | return 0 326 | } 327 | 328 | die() { 329 | error "$@" 330 | cleanup 331 | exit 1 332 | } 333 | -------------------------------------------------------------------------------- /newapkbuild.1.scd: -------------------------------------------------------------------------------- 1 | newapkbuild(1) 2 | 3 | # NAME 4 | 5 | *newapkbuild* - generate a new APKBUILD 6 | 7 | 8 | # SYNOPSIS 9 | 10 | *newapkbuild* _options_... [_pkgname_[-_pkgver_] | _source_url_] 11 | 12 | 13 | # DESCRIPTION 14 | 15 | *newapkbuild* generates a new APKBUILD for use with abuild(1). _pkgname_ 16 | specifies the package name, if not already specified with *-n*. If followed 17 | by a dash (-) and a valid version string _pkgver_, additionally specify 18 | the package's version. 19 | 20 | *newapkbuild* will try to automatically detect the build system by inspecting 21 | the source directory if _source_url_ is specified, and write out typical 22 | build instructions for that build system. If you do not specify the source 23 | URL, or want to override auto-detection, you may specify the build system 24 | with the appropriate option. If no _source_url_ and no option are specified, 25 | the generated APKBUILD file will not contain any build instructions. 26 | 27 | 28 | # OPTIONS 29 | 30 | *-a* 31 | Specifies that the package uses autotools. 32 | 33 | *-C* 34 | Specifies that the package uses CMake. CMake will be added to 35 | the makedepends. 36 | 37 | *-c* 38 | Causes *newapkbuild* to additionally copy an init.d script, conf.d 39 | file, and sample pre- and post- install scripts to the APKBUILD 40 | directory. This allows you to have a quick start for daemon 41 | packages. See the FILES section for details. 42 | 43 | *-d* _DESC_ 44 | Specifies the description (pkgdesc=) for the new package. 45 | 46 | *-e*, *-y* 47 | Specifies that the package uses a Python PEP517 build 48 | system. Python's gpep517, setuptools and wheel will be added 49 | to the makedepends. 50 | 51 | *-f* 52 | Forces *newapkbuild* to overwrite an existing APKBUILD, if one 53 | already exists in the package directory. 54 | 55 | *-h* 56 | Displays usage information. 57 | 58 | *-l* _LICENSE_ 59 | Specifies the license under which the new package is distributed. This 60 | should match an SPDX Identifier. 61 | 62 | *-m* 63 | Specifies that the package uses Meson. Meson will be added to 64 | the makedepends. 65 | 66 | *-n* _NAME_ 67 | Specifies the name of the new package. A new directory called _NAME_ 68 | will be created in the current directory, with the APKBUILD file. 69 | 70 | *-p* 71 | Specifies that the package uses a Perl Makefile.PL file. The CPAN 72 | template will be used and Perl will be added to the depends. 73 | 74 | *-r* 75 | Specifies that the package uses Cargo. Cargo will be added to 76 | the makedepends. 77 | 78 | *-s* 79 | Create an automatic SourceForge URL for the package based on its 80 | name and version. This is only valid if _pkgname-pkgver_ is specified 81 | on the command line. 82 | 83 | *-u* _URL_ 84 | Specifies the Web page (url=) for the new package. This should _not_ 85 | be the source package URL; it should be the project's main Web page. 86 | 87 | 88 | # FILES 89 | 90 | All files generated will be places in a _pkgname_ directory inside the 91 | current working directory, with _pkgname_ being created if it does not exist. 92 | 93 | APKBUILD 94 | *newapkbuild* will create an APKBUILD with the details gathered 95 | from the invocation of *newapkbuild*, and introspection of the 96 | downloaded package source if _source_url_ is provided. For more 97 | information about APKBUILD and its format, see APKBUILD(5). 98 | 99 | _pkgname_.initd 100 | If *-c* is given, *newapkbuild* will create _pkgname_.initd with 101 | example data to assist in the creation of an init.d script for 102 | a daemon. 103 | 104 | _pkgname_.confd 105 | If *-c* is given, *newapkbuild* will create _pkgname_.confd to 106 | assist in the creation of a conf.d file for a daemon, used by 107 | init.d scripts. conf.d files are used to configure init.d scripts; 108 | for more information, see openrc(8) and rc_config(3). 109 | 110 | _pkgname_.pre-install 111 | If *-c* is given, *newapkbuild* will create _pkgname_.pre-install, 112 | the contents of which will be run by apk(8) before the package 113 | is installed. 114 | 115 | _pkgname_.post-install 116 | If *-c* is given, *newapkbuild* will create _pkgname_.post-install, 117 | the contents of which will be run by apk(8) after the package is 118 | successfully installed. For more information about apk install hooks, 119 | consult the apk(8) manual. 120 | 121 | 122 | # EXAMPLES 123 | 124 | ``` 125 | newapkbuild \\ 126 | -n sharutils \\ 127 | -d "Utilities for manipulating shell archives" \\ 128 | -l "GPL-3.0+" \\ 129 | -u "https://www.gnu.org/software/sharutils/" \\ 130 | -a \\ 131 | "https://ftp.gnu.org/gnu/sharutils/sharutils-4.15.2.tar.xz" 132 | ``` 133 | 134 | 135 | # SEE ALSO 136 | 137 | SPDX license reference (on the Web at ), 138 | abuild(1), apk(8), APKBUILD(5). 139 | 140 | 141 | # AUTHORS 142 | 143 | *newapkbuild*: Natanael Copa <_ncopa@alpinelinux.org_> 144 | 145 | Documentation:++ 146 | A. Wilcox <_wilfox@adelielinux.org_> 147 | -------------------------------------------------------------------------------- /newapkbuild.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # newapkbuild - generate a new APKBUILD 4 | # Copyright (c) 2009 Natanael Copa 5 | # 6 | # Distributed under GPL-2.0-only 7 | # 8 | 9 | program_version=@VERSION@ 10 | sharedir=${ABUILD_SHAREDIR:-@sharedir@} 11 | 12 | if ! [ -f "$sharedir/functions.sh" ]; then 13 | echo "$sharedir/functions.sh: not found" >&2 14 | exit 1 15 | fi 16 | . "$sharedir/functions.sh" 17 | 18 | 19 | is_url() { 20 | case "$1" in 21 | http://*|https://*|ftp://*) return 0;; 22 | esac 23 | return 1 24 | } 25 | 26 | is_github_url() { 27 | case $1 in 28 | https://github.com/*/*/archive/*.tar.gz) return 0;; 29 | esac 30 | return 1 31 | } 32 | 33 | prepare_rust() { 34 | cat >>APKBUILD<<__EOF__ 35 | cargo fetch --target="\$CTARGET" --locked 36 | __EOF__ 37 | } 38 | 39 | # Build sections 40 | build_make() { 41 | cat >>APKBUILD<<__EOF__ 42 | make 43 | __EOF__ 44 | } 45 | 46 | build_autotools() { 47 | cat >>APKBUILD<<__EOF__ 48 | ./configure \\ 49 | --build=\$CBUILD \\ 50 | --host=\$CHOST \\ 51 | --prefix=/usr \\ 52 | --sysconfdir=/etc \\ 53 | --mandir=/usr/share/man \\ 54 | --localstatedir=/var 55 | make 56 | __EOF__ 57 | } 58 | 59 | build_cmake() { 60 | # References: 61 | # http://www.cmake.org/Wiki/CMake_Useful_Variables 62 | # http://www.vtk.org/Wiki/CMake_Cross_Compiling 63 | # This is incomplete: CMAKE_{HOST_,}SYSTEM_PROCESSOR needs to be set, 64 | # and likewise CMAKE_FIND_ROOT_PATH and a few other details. 65 | 66 | cat >>APKBUILD<<__EOF__ 67 | if [ "\$CBUILD" != "\$CHOST" ]; then 68 | local crossopts="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux" 69 | fi 70 | cmake -B build -G Ninja \\ 71 | -DCMAKE_INSTALL_PREFIX=/usr \\ 72 | -DCMAKE_INSTALL_LIBDIR=lib \\ 73 | -DBUILD_SHARED_LIBS=ON \\ 74 | -DCMAKE_BUILD_TYPE=None \\ 75 | \$crossopts 76 | cmake --build build 77 | __EOF__ 78 | } 79 | 80 | build_meson() { 81 | # References: 82 | # http://mesonbuild.com/Reference-manual.html 83 | # http://mesonbuild.com/Cross-compilation.html 84 | 85 | cat >>APKBUILD<<__EOF__ 86 | abuild-meson \\ 87 | output . 88 | meson compile -C output 89 | __EOF__ 90 | } 91 | 92 | build_perl() { 93 | cat >>APKBUILD<<__EOF__ 94 | perl Makefile.PL INSTALLDIRS=vendor 95 | make 96 | __EOF__ 97 | } 98 | 99 | build_python() { 100 | cat >>APKBUILD<<__EOF__ 101 | gpep517 build-wheel \\ 102 | --wheel-dir .dist \\ 103 | --output-fd 3 3>&1 >&2 104 | __EOF__ 105 | } 106 | 107 | build_rust() { 108 | cat >>APKBUILD<<__EOF__ 109 | cargo auditable build --frozen --release 110 | __EOF__ 111 | } 112 | 113 | build_empty() { 114 | cat >>APKBUILD<<__EOF__ 115 | # Replace with proper build command(s). 116 | # Remove if there is no build command. 117 | : 118 | __EOF__ 119 | } 120 | 121 | # Check sections 122 | check_make() { 123 | cat >>APKBUILD<<__EOF__ 124 | make check 125 | __EOF__ 126 | } 127 | 128 | check_cmake() { 129 | cat >>APKBUILD<<__EOF__ 130 | ctest --test-dir build 131 | __EOF__ 132 | } 133 | 134 | check_python() { 135 | cat >>APKBUILD<<__EOF__ 136 | python3 -m venv --clear --without-pip --system-site-packages .testenv 137 | .testenv/bin/python3 -m installer .dist/*.whl 138 | .testenv/bin/python3 -m pytest 139 | __EOF__ 140 | } 141 | 142 | check_empty() { 143 | cat >>APKBUILD<<__EOF__ 144 | # Replace with proper check command(s). 145 | # Remove and add !check option if there is no check command. 146 | : 147 | __EOF__ 148 | } 149 | 150 | check_meson() { 151 | cat >>APKBUILD<<__EOF__ 152 | meson test --print-errorlogs -C output 153 | __EOF__ 154 | } 155 | 156 | check_rust() { 157 | cat >>APKBUILD<<__EOF__ 158 | cargo test --frozen 159 | __EOF__ 160 | } 161 | 162 | # Package sections 163 | package_make() { 164 | cat >>APKBUILD<<__EOF__ 165 | make DESTDIR="\$pkgdir" install 166 | __EOF__ 167 | } 168 | 169 | package_cmake() { 170 | cat >>APKBUILD<<__EOF__ 171 | DESTDIR="\$pkgdir" cmake --install build 172 | __EOF__ 173 | } 174 | 175 | package_autotools() { 176 | package_make 177 | } 178 | 179 | package_meson() { 180 | cat >>APKBUILD<<__EOF__ 181 | DESTDIR="\$pkgdir" meson install --no-rebuild -C output 182 | __EOF__ 183 | } 184 | 185 | package_perl() { 186 | cat >>APKBUILD<<__EOF__ 187 | make DESTDIR="\$pkgdir" install 188 | find "\$pkgdir" \\( -name perllocal.pod -o -name .packlist \\) -delete 189 | __EOF__ 190 | } 191 | 192 | package_python() { 193 | cat >>APKBUILD<<__EOF__ 194 | python3 -m installer -d "\$pkgdir" \\ 195 | .dist/*.whl 196 | __EOF__ 197 | } 198 | 199 | package_empty() { 200 | cat >>APKBUILD<<__EOF__ 201 | # Replace with proper package command(s) 202 | : 203 | __EOF__ 204 | } 205 | 206 | package_rust() { 207 | cat >>APKBUILD<<__EOF__ 208 | # Replace with proper package command(s) 209 | : 210 | __EOF__ 211 | } 212 | 213 | # Create new aport from templates 214 | newaport() { 215 | local newname="${1##*/}" 216 | local pn=${newname%[-_][0-9]*} 217 | local prearchive postarchive pv 218 | local source= 219 | is_url "$1" && source="$1" 220 | 221 | if is_github_url $source; then 222 | if [ -z "$pkgname" ]; then 223 | pkgname=${source%/archive/*} 224 | pkgname=${pkgname##*/} 225 | fi 226 | pv=${newname%.t*} #strip .tar.gz .tgz .tar.bz2 etc 227 | pv=${pv#*[a-z]} 228 | prearchive=${source%/archive/*} 229 | postarchive=${source#*/archive/} 230 | postarchive=${postarchive#refs/tags/} 231 | source="${prearchive}/archive/${postarchive}" 232 | source="${source%.t*}/$pkgname-$pv.tar.gz" 233 | elif [ "$pn" != "$newname" ]; then 234 | pv=${newname#$pn[-_]} 235 | pv=${pv%.t*} #strip .tar.gz .tgz .tar.bz2 etc 236 | fi 237 | if [ -z "$pkgname" ]; then 238 | pkgname=$pn 239 | fi 240 | if [ -e "$pkgname"/APKBUILD ] && [ -z "$force" ]; then 241 | error "$pkgname/APKBUILD already exists" 242 | return 1 243 | fi 244 | mkdir -p "$pkgname" 245 | cd "$pkgname" 246 | 247 | if [ -z "$source" ] && [ -n "$sourceforge" ]; then 248 | source="https://downloads.sourceforge.net/$pn/$pn-$pv.tar.gz" 249 | fi 250 | 251 | if [ -z "$depends" ] && [ "$buildtype" = "perl" ]; then 252 | depends="perl" 253 | fi 254 | 255 | if [ -z "$checkdepends" ] && [ "$buildtype" = "python"* ]; then 256 | checkdepends="py3-pytest" 257 | fi 258 | 259 | case "$buildtype" in 260 | python) makedepends="py3-gpep517 py3-setuptools py3-wheel";; 261 | cmake) makedepends="cmake samurai";; 262 | meson) makedepends="meson";; 263 | rust) makedepends="cargo cargo-auditable";; 264 | *) makedepends="\$depends_dev";; 265 | esac 266 | 267 | # Replace pkgver in $source 268 | if [ -n "$source" ]; then 269 | source=$(echo "$source" | sed "s/$pv/\$pkgver/g") 270 | fi 271 | 272 | # Copy init.d scripts if requested 273 | if [ -n "$cpinitd" ]; then 274 | cp "$sharedir"/sample.initd $pkgname.initd 275 | cp "$sharedir"/sample.confd $pkgname.confd 276 | cp "$sharedir"/sample.pre-install $pkgname.pre-install 277 | cp "$sharedir"/sample.post-install $pkgname.post-install 278 | install="\$pkgname.pre-install \$pkgname.post-install" 279 | source="$source 280 | $pkgname.initd 281 | $pkgname.confd 282 | " 283 | fi 284 | 285 | # Generate header with standard variables 286 | cat >APKBUILD<<__EOF__ 287 | # Contributor:${PACKAGER:+" "}${PACKAGER} 288 | # Maintainer:${MAINTAINER:+" "}${MAINTAINER} 289 | pkgname=$pkgname 290 | pkgver=$pv 291 | pkgrel=0 292 | pkgdesc="$pkgdesc" 293 | url="$url" 294 | arch="all" 295 | license="$license" 296 | depends="$depends" 297 | depends_dev="" 298 | makedepends="$makedepends" 299 | checkdepends="$checkdepends" 300 | install="$install" 301 | subpackages="\$pkgname-dev \$pkgname-doc" 302 | source="$source" 303 | __EOF__ 304 | 305 | abuild -f fetch checksum unpack 306 | # Figure out the builddir 307 | for i in src/*; do 308 | if [ -d "$i" ]; then 309 | sdir=$i 310 | builddir=$(echo ${i#*/} | sed "s/$pv/\$pkgver/g") 311 | fi 312 | done 313 | printf 'builddir="$srcdir/%s"\n\n' "$builddir" >> APKBUILD 314 | 315 | # Subpackage -dev is usually required only for C/C++. Since depends_dev 316 | # confuses a lot people, remove it if there's no .h or .hpp file. 317 | find "$sdir" -name "*.h" -o -name "*.hpp" -maxdepth 3 2>/dev/null \ 318 | | head -n 1 | grep -q ".*" \ 319 | || sed -i -e '/^depends_dev=.*/d' -e 's/\$depends_dev\s*//' APKBUILD 320 | 321 | # Try to autodetect the buildtype 322 | if [ -z "$buildtype" ]; then 323 | if [ -x "$sdir"/configure ]; then 324 | buildtype="autotools" 325 | elif [ -r "$sdir"/Makefile.PL ] || [ "${pn#perl-}" != "$pn" ]; then 326 | buildtype="perl" 327 | elif [ -r "$sdir"/waf ]; then 328 | buildtype="waf" 329 | elif [ -r "$sdir"/meson.build ]; then 330 | buildtype="meson" 331 | elif [ -d "$sdir"/cmake ] || [ -r "$sdir/CMakeLists.txt" ]; then 332 | buildtype="cmake" 333 | elif [ -r "$sdir"/Makefile ]; then 334 | buildtype="make" 335 | elif [ -r "$sdir"/pyproject.toml ] || [ -r "$sdir"/setup.py ] || [ "${pn#py[0-9]-}" != "$pn" ]; then 336 | buildtype="python" 337 | elif [ -r "$sdir"/Cargo.toml ]; then 338 | buildtype="rust" 339 | fi 340 | fi 341 | 342 | case "$buildtype" in 343 | rust) 344 | cat >>APKBUILD<<__EOF__ 345 | prepare() { 346 | default_prepare 347 | 348 | __EOF__ 349 | prepare_rust 350 | cat >>APKBUILD<<__EOF__ 351 | } 352 | 353 | __EOF__ 354 | ;; 355 | esac 356 | 357 | # Create build() function 358 | cat >>APKBUILD<<__EOF__ 359 | build() { 360 | __EOF__ 361 | 362 | case "$buildtype" in 363 | make) 364 | build_make;; 365 | cmake) 366 | build_cmake;; 367 | meson) 368 | build_meson;; 369 | autotools) 370 | build_autotools;; 371 | perl) 372 | build_perl;; 373 | python) 374 | build_python;; 375 | rust) 376 | build_rust;; 377 | *) 378 | build_empty;; 379 | esac 380 | 381 | cat >>APKBUILD<<__EOF__ 382 | } 383 | 384 | __EOF__ 385 | 386 | # Create check() function 387 | cat >>APKBUILD<<__EOF__ 388 | check() { 389 | __EOF__ 390 | 391 | case "$buildtype" in 392 | make|autotools|perl) 393 | check_make;; 394 | cmake) 395 | check_cmake;; 396 | meson) 397 | check_meson;; 398 | python) 399 | check_python;; 400 | rust) 401 | check_rust;; 402 | *) 403 | check_empty;; 404 | esac 405 | 406 | cat >>APKBUILD<<__EOF__ 407 | } 408 | 409 | __EOF__ 410 | 411 | # Create package() function 412 | cat >>APKBUILD<<__EOF__ 413 | package() { 414 | __EOF__ 415 | 416 | case "$buildtype" in 417 | make) 418 | package_make;; 419 | cmake) 420 | package_cmake;; 421 | autotools) 422 | package_autotools;; 423 | meson) 424 | package_meson;; 425 | perl) 426 | package_perl;; 427 | python) 428 | package_python;; 429 | rust) 430 | package_rust;; 431 | *) 432 | package_empty;; 433 | esac 434 | 435 | if [ -n "$cpinitd" ]; then 436 | cat >>APKBUILD<<__EOF__ 437 | 438 | install -m755 -D "\$srcdir"/\$pkgname.initd \\ 439 | "\$pkgdir"/etc/init.d/\$pkgname 440 | install -m644 -D "\$srcdir"/\$pkgname.confd \\ 441 | "\$pkgdir"/etc/conf.d/\$pkgname 442 | __EOF__ 443 | fi 444 | cat >>APKBUILD<<__EOF__ 445 | } 446 | 447 | __EOF__ 448 | 449 | # regenerate checksum so they end last in APKBUILD 450 | abuild -f checksum 451 | } 452 | 453 | usage() { 454 | cat >&2 <<-__EOF__ 455 | $program $program_version - generate a new APKBUILD 456 | Usage: $program [-n PKGNAME] [-d PKGDESC] [-l LICENSE] [-u URL] 457 | [-a | -C | -m | -p | -y | -r] [-s] [-c] [-f] [-h] 458 | PKGNAME[-PKGVER] | SRCURL 459 | Options: 460 | -n Set package name to PKGNAME (only use with SRCURL) 461 | -d Set package description to PKGDESC 462 | -l Set package license to LICENSE, use identifiers from: 463 | 464 | -u Set package URL 465 | -a Create autotools package (use ./configure ...) 466 | -C Create CMake package (Assume cmake/ is there) 467 | -m Create meson package (Assume meson.build is there) 468 | -p Create perl package (Assume Makefile.PL is there) 469 | -e,-y Create python gpep517 package (Assume pyproject.toml or setup.py is there) 470 | -r Create rust package (Assume Cargo.toml is there) 471 | -s Use sourceforge source URL 472 | -c Copy a sample init.d, conf.d, and install script 473 | -f Force even if directory already exists 474 | -h Show this help 475 | __EOF__ 476 | } 477 | 478 | set_buildtype() { 479 | if [ -n "$buildtype" ]; then 480 | error "More than one buildtype flag specified ($buildtype and $1)" 481 | exit 1 482 | fi 483 | buildtype="$1" 484 | } 485 | 486 | check_arguments() { 487 | if [ $# -eq 0 ]; then 488 | error "Missing required argument: PKGNAME[-PKGVER] | SRCURL" 489 | exit 1 490 | fi 491 | if [ $# -gt 1 ]; then 492 | shift 493 | error "Unrecognized arguments: $*" 494 | exit 1 495 | fi 496 | if [ -n "$1" ] && ! is_url "$1" && [ -n "$pkgname" ]; then 497 | error "-n is only allowed when using SRCURL as last argument" 498 | exit 1 499 | fi 500 | if is_url "$1" && [ -n "$sourceforge" ]; then 501 | error "-s is only allowed when using PKGNAME as last argument" 502 | exit 1 503 | fi 504 | } 505 | 506 | while getopts "acCmd:fhl:n:pyeu:sr" opt; do 507 | case $opt in 508 | 'a') set_buildtype "autotools";; 509 | 'c') cpinitd=1;; 510 | 'C') set_buildtype "cmake";; 511 | 'm') set_buildtype "meson";; 512 | 'd') pkgdesc="$OPTARG";; 513 | 'f') force=1;; 514 | 'h') usage; exit;; 515 | 'l') license="$OPTARG";; 516 | 'n') pkgname="$OPTARG";; 517 | 'p') set_buildtype "perl";; 518 | 'y'|'e') set_buildtype "python";; 519 | 'r') set_buildtype "rust";; 520 | 'u') url="$OPTARG";; 521 | 's') sourceforge=1;; 522 | esac 523 | done 524 | shift $(( $OPTIND - 1 )) 525 | 526 | check_arguments "$@" 527 | newaport $1 528 | -------------------------------------------------------------------------------- /sample.APKBUILD: -------------------------------------------------------------------------------- 1 | # This is an example APKBUILD file. Use this as a start to creating your own, 2 | # and remove these comments. 3 | 4 | # Contributor: Your Name 5 | # Maintainer: Your Name 6 | pkgname=NAME 7 | pkgver=VERSION 8 | pkgrel=0 9 | pkgdesc="" 10 | url="" 11 | arch="all" 12 | license="unknown" 13 | depends= 14 | depends_dev= 15 | makedepends="$depends_dev" 16 | install= 17 | subpackages="$pkgname-dev $pkgname-doc" 18 | source="https://downloads.sourceforge.net/NAME/NAME-$pkgver.tar.gz" 19 | 20 | builddir="$srcdir"/$pkgname-$pkgver 21 | 22 | prepare() { 23 | default_prepare 24 | # When needed add additional preparation below. Otherwise remove this function 25 | } 26 | 27 | build() { 28 | ./configure --prefix=/usr \ 29 | --sysconfdir=/etc \ 30 | --mandir=/usr/share/man \ 31 | --infodir=/usr/share/info 32 | make 33 | } 34 | 35 | package() { 36 | make DESTDIR="$pkgdir" install 37 | 38 | # remove the 2 lines below (and this) if there is no init.d script 39 | # install -m755 -D "$srcdir"/$pkgname.initd "$pkgdir"/etc/init.d/$pkgname 40 | # install -m644 -D "$srcdir"/$pkgname.confd "$pkgdir"/etc/conf.d/$pkgname 41 | } 42 | 43 | check() { 44 | # uncomment the line below if there is a testsuite. we assume the testsuite 45 | # is run using "make check", which is the default for autotools-based build systems. 46 | # make check 47 | } 48 | 49 | sha512sums="" #generate with 'abuild checksum' 50 | -------------------------------------------------------------------------------- /sample.confd: -------------------------------------------------------------------------------- 1 | # Configuration for /etc/init.d/ 2 | 3 | # User (and group) to run as. 4 | #command_user="[:]" 5 | 6 | # Additional arguments for daemon. 7 | #command_args= 8 | 9 | # Comment out to disable process supervisor. 10 | supervisor=supervise-daemon 11 | -------------------------------------------------------------------------------- /sample.initd: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | name="SampleService" 4 | description="Sample init.d file for Alpine Linux" 5 | 6 | : "${command_user:=""}" 7 | 8 | command="/usr/sbin/" 9 | : "${command_args:="--default-args"}" 10 | command_background="yes" 11 | pidfile="/run/$RC_SVCNAME.pid" 12 | 13 | depend() { 14 | need net 15 | after firewall 16 | } 17 | -------------------------------------------------------------------------------- /sample.post-install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # add something which happens after install 4 | 5 | -------------------------------------------------------------------------------- /sample.pre-install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # add something which happens before install 4 | 5 | -------------------------------------------------------------------------------- /tests/abuild_fetch_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | abuild_fetch_help \ 6 | abuild_fetch_curl_invocation \ 7 | abuild_fetch_curl_failure \ 8 | abuild_fetch_curl_http \ 9 | abuild_fetch_wget_fallback \ 10 | abuild_fetch_wget_failure \ 11 | abuild_fetch_wget_http \ 12 | abuild_fetch_locking 13 | 14 | create_fake_curl() { 15 | mkdir bin 16 | # fake curl 17 | cat > bin/curl <<-EOF 18 | #!/bin/sh 19 | 20 | echo "[\$\$] Fake curl invoked with: \$@" 21 | if [ -n "\$STAMP" ]; then 22 | touch "\$STAMP" 23 | fi 24 | for fifo in \$FIFOS; do 25 | echo "[\$\$] waiting for fifo \$fifo" 26 | cat "\$fifo" 27 | done 28 | exit \${CURL_EXITCODE:-0} 29 | EOF 30 | chmod +x bin/curl 31 | PATH="$PWD/bin:$PATH" 32 | } 33 | 34 | create_fake_wget() { 35 | mkdir -p bin 36 | cat > bin/wget <<-EOF 37 | #!/bin/sh 38 | 39 | echo "Fake wget invoked with: \$@" 40 | exit \${WGET_EXITCODE:-0} 41 | EOF 42 | chmod +x bin/wget 43 | } 44 | 45 | abuild_fetch_help_body() { 46 | atf_check -s exit:0 \ 47 | -o not-empty \ 48 | -e empty \ 49 | abuild-fetch -h 50 | } 51 | 52 | abuild_fetch_curl_invocation_body() { 53 | create_fake_curl 54 | atf_check -s exit:0 \ 55 | -o match:"Fake curl invoked" \ 56 | -e empty \ 57 | abuild-fetch -d "$PWD" https://example.com/non-existing 58 | } 59 | 60 | abuild_fetch_curl_failure_body() { 61 | create_fake_curl 62 | # verify that fake curl works 63 | CURL_EXITCODE=1 atf_check -s exit:$CURL_EXITCODE \ 64 | -o match:"Fake curl invoked" \ 65 | curl 66 | CURL_EXITCODE=1 atf_check -s exit:$CURL_EXITCODE \ 67 | -o match:"Fake curl invoked" \ 68 | -e empty \ 69 | abuild-fetch -d "$PWD" https://example.com/non-existing 70 | } 71 | 72 | abuild_fetch_curl_http_body() { 73 | create_fake_curl 74 | atf_check -s exit:0 \ 75 | -o match:"--insecure" \ 76 | -e empty \ 77 | abuild-fetch -d "$PWD" http://example.com/non-existing 78 | } 79 | 80 | abuild_fetch_wget_fallback_body() { 81 | create_fake_wget 82 | PATH="$PWD/bin:$(atf_get_srcdir)/.." atf_check -s exit:0 \ 83 | -o match:"Fake wget invoked" \ 84 | -e empty \ 85 | abuild-fetch -d "$PWD" https://example.com/non-existing 86 | } 87 | 88 | abuild_fetch_wget_failure_body() { 89 | create_fake_wget 90 | WGET_EXITCODE=1 PATH="$PWD/bin:$(atf_get_srcdir)/.." atf_check -s exit:1 \ 91 | -o match:"Fake wget invoked" \ 92 | -e empty \ 93 | abuild-fetch -d "$PWD" https://example.com/non-existing 94 | } 95 | 96 | abuild_fetch_wget_http_body() { 97 | create_fake_wget 98 | PATH="$PWD/bin:$(atf_get_srcdir)/.." atf_check -s exit:0 \ 99 | -o match:"--no-check-certificate" \ 100 | -e empty \ 101 | abuild-fetch -d "$PWD" http://example.com/non-existing 102 | } 103 | 104 | abuild_fetch_locking_body() { 105 | create_fake_curl 106 | mkfifo waitstart1 waitstart2 done1 done2 107 | 108 | cat > bin/test-locking <<-EOF 109 | #!/bin/sh 110 | 111 | # start first instance 112 | FIFOS="waitstart1 done1" CURL_EXITCODE=1 \ 113 | abuild-fetch -d "$PWD" https://example.com/foo & 114 | pid1=\$! 115 | 116 | # block til curl is called so we dont start the second instance too early 117 | echo "block1" > waitstart1 118 | 119 | # try a second fetch, while the first one is still running 120 | FIFOS="waitstart2 done2" STAMP=stamp2 \ 121 | abuild-fetch -d "$PWD" https://example.com/foo & 122 | pid2=\$! 123 | 124 | # second instance should not start curl until first exits, so stamp2 should 125 | # not exist yet 126 | if [ -e stamp2 ]; then 127 | echo "stamp2 should not exist here" >&2 128 | exit 1 129 | fi 130 | 131 | # tell fake curl to similuate download fail of first instance 132 | echo "download 1 failed" > done1 133 | ! wait \$pid1 134 | 135 | # wait til second instance gets lock to simulate download start 136 | echo "block2" > waitstart2 137 | 138 | # retry first download. second instance should block us 139 | FIFOS="done1" STAMP=stamp3 \ 140 | abuild-fetch -d "$PWD" https://example.com/foo & 141 | pid1=\$! 142 | 143 | # give enough time for abuild-fetch to call curl 144 | sleep 0.5 145 | 146 | # the first stamp should not exist, second instance should block the retry 147 | if [ -e stamp3 ]; then 148 | echo "stamp3 should not exist here" >&2 149 | exit 1 150 | fi 151 | 152 | # simulate second download finished 153 | echo "download 2 complete" > done2 154 | wait \$pid2 155 | 156 | # first should get unblocked 157 | echo "download 3 complete" > done1 158 | wait \$pid1 159 | 160 | if ! [ -e stamp3 ]; then 161 | echo "stamp3 should exist here" >&2 162 | exit 1 163 | fi 164 | EOF 165 | 166 | atf_check -s exit:0 \ 167 | -o match:"block1" \ 168 | -o match:"download 1 failed" \ 169 | -o match:"block2" \ 170 | -o match:"download 2 complete" \ 171 | -o match:"download 3 complete" \ 172 | sh -e bin/test-locking 173 | 174 | } 175 | 176 | -------------------------------------------------------------------------------- /tests/abuild_gzsplit_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | abuild_gzsplit_3_11_package \ 6 | abuild_gzsplit_3_12_package 7 | 8 | DATADIR=$(atf_get_srcdir)/testdata 9 | 10 | check_content() { 11 | atf_check -s exit:0 \ 12 | -o match:".PKGINFO" \ 13 | tar -ztf control.tar.gz 14 | 15 | atf_check -s exit:0 \ 16 | -o match:"etc/alpine-release" \ 17 | tar -ztf data.tar.gz 18 | 19 | atf_check -s exit:0 \ 20 | -o match:".SIGN.RSA" \ 21 | tar -ztf signatures.tar.gz 22 | } 23 | 24 | abuild_gzsplit_3_11_package_body() { 25 | atf_check -s exit:0 \ 26 | abuild-gzsplit < "$DATADIR"/alpine-base-3.11.6-r0.apk 27 | check_content 28 | } 29 | 30 | abuild_gzsplit_3_12_package_body() { 31 | atf_check -s exit:0 \ 32 | abuild-gzsplit < "$DATADIR"/alpine-base-3.12.0-r0.apk 33 | check_content 34 | } 35 | -------------------------------------------------------------------------------- /tests/abuild_keygen_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | SRCDIR="$(atf_get_srcdir)" 4 | . "$SRCDIR"/test_env.sh 5 | init_tests \ 6 | abuild_keygen_help \ 7 | abuild_keygen_invalid_opts \ 8 | abuild_keygen_invalid_arg \ 9 | abuild_keygen_non_interactive \ 10 | abuild_keygen_append \ 11 | abuild_keygen_install_without_sudo \ 12 | abuild_keygen_install_interactive \ 13 | abuild_keygen_install_non_interactive \ 14 | abuild_keygen_install_doas \ 15 | abuild_keygen_kernel \ 16 | 17 | export ABUILD_SHAREDIR="$SRCDIR"/.. 18 | export ABUILD_USERDIR="$HOME"/.abuild 19 | export GIT=false 20 | export FAKEKEY="$SRCDIR/testdata/abuild.key" 21 | export FAKEKEYPUB="$SRCDIR/testdata/abuild.key.pub" 22 | 23 | PATH="$SRCDIR/bin:$PATH" 24 | 25 | abuild_keygen_help_body() { 26 | atf_check -s exit:0 \ 27 | -o not-empty \ 28 | -e empty \ 29 | abuild-keygen --help 30 | } 31 | 32 | abuild_keygen_invalid_opts_body() { 33 | atf_check -s exit:1 \ 34 | -o empty \ 35 | -e not-empty \ 36 | abuild-keygen -INVALID 37 | } 38 | 39 | abuild_keygen_invalid_arg_body() { 40 | atf_check -s exit:2 \ 41 | -o empty \ 42 | -e not-empty \ 43 | abuild-keygen INVALID 44 | } 45 | 46 | abuild_keygen_non_interactive_body() { 47 | atf_check -s exit:0 \ 48 | -o empty \ 49 | -e match:"(Generating|writing) RSA" \ 50 | abuild-keygen -n 51 | } 52 | 53 | abuild_keygen_append_body() { 54 | PACKAGER="Test User " \ 55 | atf_check -s exit:0 \ 56 | \ 57 | -o empty \ 58 | -e match:"(Generating|writing) RSA" \ 59 | abuild-keygen --append -n 60 | grep '^PACKAGER_PRIVKEY=.*user@example.com' "$HOME"/.abuild/abuild.conf \ 61 | || atf_fail 'PACKAGER_PRIVKEY not set in abuild.conf' 62 | } 63 | 64 | abuild_keygen_install_without_sudo_body() { 65 | SUDO=false \ 66 | atf_check -s exit:1 \ 67 | \ 68 | -o empty \ 69 | -e match:"(Generating|writing) RSA" \ 70 | abuild-keygen --install -n 71 | } 72 | 73 | abuild_keygen_install_interactive_body() { 74 | echo | abuild_keygen_install_root="$PWD" SUDO= \ 75 | atf_check -s exit:0 \ 76 | \ 77 | -o match:"Enter file" \ 78 | -e match:"(Generating|writing) RSA" \ 79 | abuild-keygen --install 80 | } 81 | 82 | abuild_keygen_install_non_interactive_body() { 83 | abuild_keygen_install_root="$PWD" SUDO= \ 84 | atf_check -s exit:0 \ 85 | \ 86 | -o empty \ 87 | -e match:"(Generating|writing) RSA" \ 88 | abuild-keygen --install -n 89 | } 90 | 91 | abuild_keygen_install_doas_body() { 92 | mkdir bin 93 | cat >bin/doas<<-EOF 94 | #!/bin/sh 95 | echo "fake doas" 96 | "\$@" 97 | EOF 98 | chmod +x bin/doas 99 | 100 | PATH="$PWD/bin:$PATH" abuild_keygen_install_root="$PWD" \ 101 | atf_check -s exit:0 \ 102 | \ 103 | -o match:"fake doas" \ 104 | -e match:"(Generating|writing) RSA" \ 105 | abuild-keygen --install -n 106 | } 107 | 108 | abuild_keygen_kernel_body() { 109 | atf_check -s exit:0 \ 110 | -e match:"(Generating|writing) RSA" \ 111 | -e match:"signing key was created:.*kernel_signing_key.pem" \ 112 | -e match:"KERNEL_SIGNING_KEY=.*was added to.*abuild.conf" \ 113 | abuild-keygen --kernel 114 | grep '^KERNEL_SIGNING_KEY=.*' "$HOME"/.abuild/abuild.conf \ 115 | || atf_fail 'KERNEL_SIGNING_KEY not set in abuild.conf' 116 | test -f "$HOME"/.abuild/kernel_signing_key.pem \ 117 | || atf_fail '$HOME/.abuild/kernel_signing_key.pem was not created' 118 | } 119 | -------------------------------------------------------------------------------- /tests/abuild_sign_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | abuild_sign_help \ 6 | abuild_sign_invalid_opt \ 7 | abuild_sign_missing_arg \ 8 | abuild_sign_installed_missing \ 9 | abuild_sign_installed_missing_pub \ 10 | abuild_sign_installed_missing_priv \ 11 | abuild_sign_installed \ 12 | abuild_sign_owner_type_invalid \ 13 | abuild_sign_owner_type_default \ 14 | abuild_sign_owner_type_rsa \ 15 | abuild_sign_owner_type_rsa256 16 | 17 | export ABUILD_SHAREDIR="$(atf_get_srcdir)/.." 18 | export ABUILD_USERDIR="$HOME"/.abuild 19 | 20 | init_keys() { 21 | cp -Ra "$(atf_get_srcdir)"/testdata/.abuild "$PWD" 22 | } 23 | 24 | abuild_sign_help_body() { 25 | atf_check -s exit:0 \ 26 | -o match:"Usage:" \ 27 | abuild-sign --help 28 | } 29 | 30 | abuild_sign_invalid_opt_body() { 31 | atf_check -s exit:2 \ 32 | -e match:"Usage:" \ 33 | abuild-sign -INVALID 34 | } 35 | 36 | abuild_sign_missing_arg_body() { 37 | atf_check -s exit:2 \ 38 | -e match:"Usage:" \ 39 | abuild-sign 40 | } 41 | 42 | abuild_sign_installed_missing_body() { 43 | atf_check -s exit:1 \ 44 | -e match:"No private key found" \ 45 | abuild-sign --installed 46 | } 47 | 48 | abuild_sign_installed_missing_pub_body() { 49 | init_keys 50 | rm .abuild/*.rsa.pub 51 | atf_check -s exit:1 \ 52 | -e match:"rsa.pub: File not found" \ 53 | abuild-sign --installed 54 | } 55 | 56 | abuild_sign_installed_missing_priv_body() { 57 | init_keys 58 | rm .abuild/*.rsa 59 | atf_check -s exit:1 \ 60 | -e match:"rsa: File not found" \ 61 | abuild-sign --installed 62 | } 63 | 64 | abuild_sign_installed_body() { 65 | init_keys 66 | atf_check -s exit:0 \ 67 | abuild-sign --installed 68 | } 69 | 70 | abuild_sign_owner_type_invalid_body() { 71 | init_keys 72 | atf_check -s exit:1 \ 73 | -e match:"abuild-sign: supported types are RSA and RSA256" \ 74 | abuild-sign -t DSA foo.tar.gz 75 | } 76 | 77 | abuild_sign_owner_type_default_body() { 78 | init_keys 79 | echo foo > .PKGINFO 80 | tar -zcf foo.tar.gz .PKGINFO || atf_fail "Failed to create unsigned test archive" 81 | 82 | atf_check -s exit:0 \ 83 | -e match:"Signed" \ 84 | abuild-sign foo.tar.gz 85 | 86 | atf_check -s exit:0 \ 87 | -o match:"0/0.*\.SIGN\.RSA\." \ 88 | tar -ztvf foo.tar.gz 89 | } 90 | 91 | abuild_sign_owner_type_rsa_body() { 92 | init_keys 93 | echo foo > .PKGINFO 94 | tar -zcf foo.tar.gz .PKGINFO || atf_fail "Failed to create unsigned test archive" 95 | 96 | atf_check -s exit:0 \ 97 | -e match:"Signed" \ 98 | abuild-sign -t RSA foo.tar.gz 99 | 100 | atf_check -s exit:0 \ 101 | -o match:"0/0.*\.SIGN\.RSA\." \ 102 | tar -ztvf foo.tar.gz 103 | } 104 | 105 | abuild_sign_owner_type_rsa256_body() { 106 | init_keys 107 | echo foo > .PKGINFO 108 | tar -zcf foo.tar.gz .PKGINFO || atf_fail "Failed to create unsigned test archive" 109 | 110 | atf_check -s exit:0 \ 111 | -e match:"Signed" \ 112 | abuild-sign -t RSA256 foo.tar.gz 113 | 114 | atf_check -s exit:0 \ 115 | -o match:"0/0.*\.SIGN\.RSA256\." \ 116 | tar -ztvf foo.tar.gz 117 | } 118 | -------------------------------------------------------------------------------- /tests/abuild_tar_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | abuild_tar_help \ 6 | abuild_tar_invalid_opt \ 7 | abuild_tar_cut \ 8 | abuild_tar_hash 9 | 10 | DATADIR=$(atf_get_srcdir)/testdata 11 | 12 | abuild_tar_help_body() { 13 | atf_check -s exit:0 \ 14 | -o match:"usage:" \ 15 | abuild-tar --help 16 | } 17 | 18 | abuild_tar_invalid_opt_body() { 19 | atf_check -s not-exit:0 \ 20 | -e match:"usage:" \ 21 | abuild-tar --invalid 22 | } 23 | 24 | abuild_tar_cut_body() { 25 | atf_require_prog tar 26 | 27 | echo foo > foo 28 | echo bar > bar 29 | tar -cf foo.tar foo 30 | tar -cf bar.tar bar 31 | 32 | cat foo.tar bar.tar > foobar.tar 33 | atf_check -o not-match:bar \ 34 | tar -tf foobar.tar 35 | 36 | tar -cf - foo | abuild-tar --cut > cutted.tar 37 | cat cutted.tar bar.tar > foobar.tar 38 | atf_check -o match:bar \ 39 | tar -tf foobar.tar 40 | } 41 | 42 | abuild_tar_hash_body() { 43 | atf_require_prog tar strings 44 | 45 | echo foo > foo 46 | tar --format=posix -cf - foo | abuild-tar --hash > foo.tar 47 | atf_check -o match:foo tar -tvf foo.tar 48 | atf_check -o match:"APK-TOOLS.checksum" strings foo.tar 49 | } 50 | -------------------------------------------------------------------------------- /tests/abump_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | abump_help \ 6 | abump_invalid_opt \ 7 | abump_missing_args \ 8 | abump_simple_bump \ 9 | abump_isolates_apkbuild 10 | 11 | export ABUILD_SHAREDIR=$(atf_get_srcdir)/.. 12 | export GIT_CONFIG_GLOBAL="$(atf_get_srcdir)/testdata/gitconfig" 13 | export APORTSDIR="$PWD" 14 | export ABUILD_OPTS="" 15 | export ABUILD_APK_INDEX_OPTS="--allow-untrusted" 16 | export REPODEST="$PWD"/packages 17 | 18 | abump_help_body() { 19 | atf_check -s exit:0 \ 20 | -o match:"Usage" \ 21 | abump -h 22 | } 23 | 24 | abump_invalid_opt_body() { 25 | atf_check -s exit:2 \ 26 | -e match:"Usage" \ 27 | abump -@ 28 | } 29 | 30 | abump_missing_args_body() { 31 | atf_check -s exit:2 \ 32 | -e match:"Usage" \ 33 | abump 34 | } 35 | 36 | abump_simple_bump_body() { 37 | cp -R "$(atf_get_srcdir)"/testdata/.abuild . 38 | git init 39 | mkdir -p main/foo 40 | cd main/foo 41 | echo "first" > foo-1.0.txt 42 | cat > APKBUILD <<-EOF 43 | # Maintainer: Test user 44 | pkgname="foo" 45 | pkgver=1.0 46 | pkgrel=0 47 | pkgdesc="dummy package for test" 48 | url="https://alpinelinux.org" 49 | license="MIT" 50 | arch="noarch" 51 | source="foo-\$pkgver.txt" 52 | options="!check" 53 | package() { 54 | install -D "\$srcdir"/foo-\$pkgver.txt "\$pkgdir"/foo 55 | } 56 | EOF 57 | abuild checksum 58 | abuild -d 59 | git add APKBUILD foo-1.0.txt 60 | git commit -m "test commit" 61 | 62 | echo "second" > foo-1.1.txt 63 | export ABUILD_OPTS="-d" 64 | atf_check \ 65 | -o match:"foo-1.1.txt: OK" \ 66 | -e match:"upgrade to 1.1" \ 67 | abump foo-1.1 68 | 69 | atf_check -s exit:1 \ 70 | -e match:">>> ERROR: version is already 1.1" \ 71 | abump foo-1.1 72 | 73 | sed -i -e 's/pkgver=.*/pkgver=1.2/' APKBUILD 74 | echo "third" > foo-1.2.txt 75 | atf_check \ 76 | -o match:"foo-1.2.txt: OK" \ 77 | -e match:"upgrade to 1.2" \ 78 | abump foo-1.2 79 | } 80 | 81 | abump_isolates_apkbuild_body() { 82 | cp -R "$(atf_get_srcdir)"/testdata/.abuild . 83 | git init 84 | mkdir -p main/bar 85 | cd main/bar 86 | echo "first" > bar-1.0.txt 87 | cat > APKBUILD <<-"EOF" 88 | # Maintainer: Test user 89 | pkgname="bar" 90 | pkgver=1.0 91 | pkgrel=0 92 | pkgdesc="dummy package for test" 93 | url="https://alpinelinux.org" 94 | license="MIT" 95 | arch="noarch" 96 | source="bar-$pkgver.txt" 97 | options="!check" 98 | 99 | export BUILDFLAGS="${BUILDFLAGS:-"repo=$repo"}" 100 | 101 | package() { 102 | echo "BUILDFLAGS: $BUILDFLAGS" 103 | install -D "$srcdir"/bar-$pkgver.txt "$pkgdir"/bar 104 | } 105 | EOF 106 | abuild checksum 107 | abuild -d 108 | git add APKBUILD bar-1.0.txt 109 | git commit -m "test commit" 110 | 111 | echo "second" > bar-1.1.txt 112 | export ABUILD_OPTS="-d" 113 | atf_check \ 114 | -o match:"BUILDFLAGS: repo=main" \ 115 | -e ignore \ 116 | abump bar-1.1 117 | } 118 | -------------------------------------------------------------------------------- /tests/apkgrel_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | apkgrel_usage 6 | 7 | export ABUILD_SHAREDIR=$(atf_get_srcdir)/.. 8 | 9 | apkgrel_usage_body() { 10 | atf_check -o match:"usage" apkgrel -h 11 | atf_check -s exit:2 -e match:"usage" apkgrel -Z 12 | } 13 | 14 | -------------------------------------------------------------------------------- /tests/bin/openssl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # fake openssl 4 | while [ $# -gt 0 ]; do 5 | case "$1" in 6 | genrsa|rsa|req) 7 | cmd="$1" 8 | ;; 9 | -config) 10 | shift 11 | config="$1" 12 | ;; 13 | -out) 14 | shift 15 | outfile="$1" 16 | ;; 17 | -in) 18 | shift 19 | infile="$1" 20 | esac 21 | shift 22 | done 23 | 24 | case "$cmd" in 25 | genrsa) 26 | cat "$FAKEKEY" > "$outfile" 27 | ;; 28 | rsa) 29 | echo "writing RSA key" >&2 30 | cat "$FAKEKEYPUB" > "$outfile" 31 | ;; 32 | req) 33 | echo "Using configuration from $config" >&2 34 | echo "Generating RSA key with 4096 bits" >&2 35 | echo "Writing private key to '$outfile'" >&2 36 | cat "$FAKEKEY" "$FAKEKEYPUB" > "$outfile" 37 | ;; 38 | *) 39 | echo "unimplemented fake openssl command: $cmd" >&2 40 | exit 1 41 | ;; 42 | 43 | esac 44 | 45 | -------------------------------------------------------------------------------- /tests/checkapk_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | checkapk_help \ 6 | checkapk_invalid_opt \ 7 | checkapk_missing_abuild_conf \ 8 | checkapk_missing_apkbuild 9 | 10 | DATADIR=$(atf_get_srcdir)/testdata 11 | 12 | export ABUILD_SHAREDIR=$(atf_get_srcdir)/.. 13 | export ABUILD_CONF=/dev/null 14 | export ABUILD_USERCONF=/dev/null 15 | 16 | checkapk_help_body() { 17 | atf_check -s exit:0 \ 18 | -o match:"Usage:" \ 19 | checkapk --help 20 | } 21 | 22 | checkapk_invalid_opt_body() { 23 | atf_check -s not-exit:0 \ 24 | -e match:"Usage:" \ 25 | checkapk --invalid 26 | } 27 | 28 | checkapk_missing_abuild_conf_body() { 29 | ABUILD_DEFCONF=/dev/null atf_check \ 30 | -s not-exit:0 \ 31 | -e match:"no abuild.conf found" \ 32 | checkapk 33 | } 34 | 35 | checkapk_missing_apkbuild_body() { 36 | atf_check \ 37 | -s not-exit:0 \ 38 | -e match:"must be run in the directory of a built package" \ 39 | checkapk 40 | } 41 | -------------------------------------------------------------------------------- /tests/functions_test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env atf-sh 2 | 3 | . $(atf_get_srcdir)/test_env.sh 4 | init_tests \ 5 | funcs_check_CBUILD \ 6 | funcs_check_missing_gcc \ 7 | funcs_check_missing_apk \ 8 | funcs_check_missing_git \ 9 | funcs_check_env_set_but_empty \ 10 | funcs_check_defconfig 11 | 12 | FUNCS=$(atf_get_srcdir)/../functions.sh 13 | 14 | funcs_check_CBUILD_body() { 15 | atf_check -s exit:0 \ 16 | -o not-empty \ 17 | -e empty \ 18 | sh -e -c " . $FUNCS; echo \"\$CBUILD\"" 19 | } 20 | 21 | funcs_check_missing_gcc_body() { 22 | atf_check -s exit:0 \ 23 | sh -e -c "CC=false; . $FUNCS && test -z \"$CBUILD\"" 24 | } 25 | 26 | funcs_check_missing_apk_body() { 27 | atf_check -s exit:1 \ 28 | -e match:"Unable to deduce build architecture" \ 29 | sh -e -c "APK=false; . $FUNCS && test -z \"$CBUILD\"" 30 | } 31 | 32 | funcs_check_missing_git_body() { 33 | atf_check -s exit:0 \ 34 | -o empty \ 35 | -e empty \ 36 | sh -e -c "GIT=false . $FUNCS" 37 | } 38 | 39 | funcs_check_env_set_but_empty_body() { 40 | for arch in aarch64 armv7 armhf ppc64le s390x x86 x86_64; do 41 | for var in CC CXX HOSTCC HOSTCXX HOSTLD BUILDCC BUILDCXX BUILDLD; do 42 | cat >script<<-EOF 43 | unset $var 44 | CHOST=$arch 45 | . $FUNCS 46 | if [ -n "\${$var+set}" ] && [ -z "\$$var" ]; then 47 | echo '$var set but empty ($arch)' 48 | fi 49 | EOF 50 | atf_check -s exit:0 \ 51 | -o empty \ 52 | -e empty \ 53 | sh script 54 | done 55 | done 56 | } 57 | 58 | funcs_check_defconfig_body() { 59 | echo "CFLAGS=defcflags" > def.conf 60 | echo "CFLAGS=syscflags" > etc.conf 61 | echo "CFLAGS=usercflags" > user.conf 62 | 63 | unset CFLAGS 64 | 65 | # test /usr/share/abuild/default.conf 66 | ABUILD_DEFCONF="$PWD"/def.conf ABUILD_CONF=/dev/null ABUILD_USERCONF=/dev/null \ 67 | atf_check -o match:"defcflags" \ 68 | sh -e -c " . $FUNCS; echo \"\$CFLAGS\"" 69 | 70 | # test /etc/abuild.conf 71 | ABUILD_DEFCONF=/dev/null ABUILD_CONF="$PWD"/etc.conf ABUILD_USERCONF=/dev/null \ 72 | atf_check \ 73 | -o match:"syscflags" \ 74 | sh -e -c " . $FUNCS; echo \"\$CFLAGS\"" 75 | 76 | # user config ($HOME/.abuild/abuild.conf) wins over /etc/abuild.conf 77 | ABUILD_DEFCONF="$PWD"/def.conf ABUILD_CONF="$PWD/etc.conf" ABUILD_USERCONF="$PWD/user.conf" \ 78 | atf_check \ 79 | -o match:"usercflags" \ 80 | sh -e -c " . $FUNCS; echo \"\$CFLAGS\"" 81 | 82 | # environment wins 83 | ABUILD_DEFCONF="$PWD"/def.conf ABUILD_CONF="$PWD/etc.conf" ABUILD_USERCONF="$PWD/user.conf" \ 84 | CFLAGS="envcflags" atf_check \ 85 | -o match:"envcflags" \ 86 | sh -e -c " . $FUNCS; echo \"\$CFLAGS\"" 87 | } 88 | -------------------------------------------------------------------------------- /tests/test_env.sh: -------------------------------------------------------------------------------- 1 | PATH=$(atf_get_srcdir)/..:$PATH 2 | 3 | init_tests() { 4 | TESTS="$@" 5 | export TESTS 6 | for t; do 7 | atf_test_case $t 8 | done 9 | } 10 | 11 | atf_init_test_cases() { 12 | for t in $TESTS; do 13 | atf_add_test_case $t 14 | done 15 | } 16 | -------------------------------------------------------------------------------- /tests/testdata/.abuild/abuild.conf: -------------------------------------------------------------------------------- 1 | PACKAGER_PRIVKEY="$HOME/.abuild/testkey-62a9ada3.rsa" 2 | -------------------------------------------------------------------------------- /tests/testdata/.abuild/testkey-62a9ada3.rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAnY3kN2ubj5i5t6pBCKbc1q6j0+ht4sBoSLsR6XtXOUFkN2o+ 3 | JJHgUtDY2m8GizrXTrmAEFZ9AUhdX4CvLW7GEPc3Nbx2updF81UU1gUI5o/L7Spt 4 | LU+R65bIXSicgj7DTDD+G9rZaIXSGCLOxspFQJDyIXGt25RY0I4u7GBPIkL8EFzp 5 | h515yX36cuTsxdKAGI6IXbwG5Jj5Q3ZvCxD85VhKu+4DmTUFfvKXP0DKC3uCo8y4 6 | tNF7ASF6Yboy1lH/k8OFtwob/NvNoLDm7pfQphbZrIcXWThoAzAafJf7iA8JoYTA 7 | nu6c1Fz48KT6+44lanESf8Soxw/apanwpgNQowIDAQABAoIBAQCLSmq9ZHE/XrKy 8 | Yd7lG0CavAMy0YZ0tc58noaTeOwAPoOvSkpuYlmEXgeZ9hY++WJowy8pQo15mNSU 9 | HlzBOfH6BdXVuCzvgdXh7xJgtErOK8sKfjvPl01WjxPM6J6Vt49JyPafAbi747N+ 10 | iydsMF9RWdP3JV2jh1+N4mYxrGPJ0TN837ujbKzhTNz52ja/KovaN6qhJn4rGdhi 11 | 2Ye0wZ05gyokMRBqTeAOlbaCZaZjfZKsD5NQEuenrc/Zji4UyJO7qmpC+gWZf0P4 12 | +DvwUTU9ovUf1zUUo0SR+AeedYY8ikR+xIzBoMFejRFTZRr/DvS5hlKJt9zLtFR/ 13 | 4n+0/YyBAoGBAM1g4xcXBSlPKcRppwH6mVf4naZ0y1uyDYlOLoeg8xEPlBA4WceQ 14 | G/M1GDeCsfFZA5HRzGbVkFw8/c4xDyMZqFz+ftWYIpxSA3Ef/Dy5GqKAtobVHRuD 15 | nZVdBiw8PDAhU0IeXQiKNmPNTd01nvojlppz8O9gVRtL1uJRNxvotNYzAoGBAMRj 16 | XBfP1fnH49nSWghxnPaMH06QDiszAQ5zWtavcaq/X14g+3rrpNKb5y6xNf+gcRdt 17 | +iwWeWBAqPfIQxuZteFpQH2oJ7QtZSjFgfAj7yZEzH2ZTtnU01raWdGXe9DV6j0A 18 | Ob+DB9iasTo7n1hlrojkmf5Be112573vkqmnYsvRAoGAc5B6GAsHB3iZCwFcTTvC 19 | v4KQyxJbP4yQG1vXyM+jFk2Kxhm/QxDu+Uo+BzZOhHzPCmVgO9keMxjKxBRM7TZJ 20 | y5IUsoG5r/ZiI2yZFV4fA6OjkXknuMy1hk9i4s8+GuMVo1XMibqj4kKq9rdublhK 21 | LTziLQAqw4JINu72MIkgAIsCgYBYrOSwe9AKcQ+ZEzpEBcjyKmMYfkNnjigz9jJW 22 | LfINP0w4nHvxDOXnky3YD3xqaG+oPKhxr9QuegPRnkNu+wD9PyE3m+4RlU3QEx6Q 23 | 6CjcBsSvEcJg6ZBlvaJA2T23FmAmGyv4JZotW+wad0GEEKW2ekJuY/LoSQBq6vo2 24 | ULZzgQKBgDtMsrNnQN0QPUA0oqXBi5LnNA3aHEB8WHGbPhlZBYYeQaltgCjj6BH/ 25 | L37pHxHa2CcH5oG0suXN43duCOSVQcvvUMx35EvB4sYrOdyFh/Jtcwr9ou9km11t 26 | Y5ODq2MnmPzcqQfOkbKKhC46fi7La/zL5R26NkD2nQJq30PNxe9g 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /tests/testdata/.abuild/testkey-62a9ada3.rsa.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnY3kN2ubj5i5t6pBCKbc 3 | 1q6j0+ht4sBoSLsR6XtXOUFkN2o+JJHgUtDY2m8GizrXTrmAEFZ9AUhdX4CvLW7G 4 | EPc3Nbx2updF81UU1gUI5o/L7SptLU+R65bIXSicgj7DTDD+G9rZaIXSGCLOxspF 5 | QJDyIXGt25RY0I4u7GBPIkL8EFzph515yX36cuTsxdKAGI6IXbwG5Jj5Q3ZvCxD8 6 | 5VhKu+4DmTUFfvKXP0DKC3uCo8y4tNF7ASF6Yboy1lH/k8OFtwob/NvNoLDm7pfQ 7 | phbZrIcXWThoAzAafJf7iA8JoYTAnu6c1Fz48KT6+44lanESf8Soxw/apanwpgNQ 8 | owIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /tests/testdata/alpine-base-3.11.6-r0.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpinelinux/abuild/1355cc9b634d953632e62c26832876b9d20c60fb/tests/testdata/alpine-base-3.11.6-r0.apk -------------------------------------------------------------------------------- /tests/testdata/alpine-base-3.12.0-r0.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alpinelinux/abuild/1355cc9b634d953632e62c26832876b9d20c60fb/tests/testdata/alpine-base-3.12.0-r0.apk -------------------------------------------------------------------------------- /tests/testdata/gitconfig: -------------------------------------------------------------------------------- 1 | [color] 2 | ui = always 3 | [user] 4 | name = Joe User 5 | email = juser@example.com 6 | -------------------------------------------------------------------------------- /tests/testrepo/dbgpkg/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname="dbgpkg" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package to test -dbg" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="all" 8 | license="MIT" 9 | subpackages="$pkgname-dbg" 10 | source="hello.c" 11 | builddir="$srcdir/dbgpkg-1.0" 12 | 13 | prepare() { 14 | mkdir -p "$builddir" 15 | cp "$srcdir"/*.c "$builddir" 16 | } 17 | 18 | build() { 19 | $CC -o hello hello.c 20 | } 21 | 22 | check() { 23 | ./hello 24 | } 25 | 26 | package() { 27 | install -D -m755 hello "$pkgdir"/usr/bin/hello 28 | ln "$pkgdir"/usr/bin/hello "$pkgdir"/usr/bin/hello-hard 29 | ln -s "$pkgdir"/usr/bin/hello "$pkgdir"/usr/bin/hello-sym 30 | } 31 | 32 | sha512sums=" 33 | e80c0d471f7ec07708795b86127f0f7c968c49031f1e57cae200b5fbf2606e55fc4d56efb05a85c6f54dfe33e87d6789154cf15aee72ba0d216f08fb57926503 hello.c 34 | " 35 | -------------------------------------------------------------------------------- /tests/testrepo/dbgpkg/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | printf("hello world\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /tests/testrepo/invalid-filename/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname="invalid-filename" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package that fails to build" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | 10 | prepare() { 11 | mkdir -p "$builddir" 12 | } 13 | 14 | build() { 15 | touch $'bad\nfile' 16 | } 17 | 18 | check() { 19 | true 20 | } 21 | 22 | package() { 23 | mkdir -p "$pkgdir" 24 | cp -R * "$pkgdir"/ 25 | } 26 | 27 | -------------------------------------------------------------------------------- /tests/testrepo/large-doc-subpkg/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname="large-doc-subpkg" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package to check if large doc subpackages cause a warning to be emitted" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | subpackages="$pkgname-doc" 10 | source="" 11 | 12 | prepare() { 13 | mkdir -p "$builddir" 14 | } 15 | 16 | build() { 17 | true 18 | } 19 | 20 | check() { 21 | true 22 | } 23 | 24 | package() { 25 | mkdir -p "$pkgdir/usr/bin" 26 | cat >"$pkgdir/usr/bin/foo" < 2 | pkgname="lib64test" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | subpackages="$pkgname-dev $pkgname-doc" 10 | source="" 11 | builddir="$srcdir/$pkgname-$pkgver" 12 | 13 | prepare() { 14 | mkdir -p "$builddir" 15 | } 16 | 17 | build() { 18 | mkdir -p usr/include usr/bin usr/share/man/man1 usr/lib64 19 | touch usr/include/$pkgname.h 20 | touch usr/bin/$pkgname 21 | touch usr/share/man/man1/$pkgname.1 22 | } 23 | 24 | check() { 25 | true 26 | } 27 | 28 | package() { 29 | mkdir -p "$pkgdir" 30 | cp -R * "$pkgdir"/ 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tests/testrepo/pkg path with spaces/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname="pkg-path-with-spaces" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package to test building with spaces in path" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="all" 8 | license="MIT" 9 | source="hello.c" 10 | builddir="$srcdir/$pkgname-1.0" 11 | 12 | prepare() { 13 | mkdir -p "$builddir" 14 | cp "$srcdir"/*.c "$builddir" 15 | } 16 | 17 | build() { 18 | $CC -o hello hello.c 19 | } 20 | 21 | check() { 22 | ./hello 23 | } 24 | 25 | package() { 26 | install -D -m755 hello "$pkgdir"/usr/bin/hello 27 | ln "$pkgdir"/usr/bin/hello "$pkgdir"/usr/bin/hello-hard 28 | ln -s "$pkgdir"/usr/bin/hello "$pkgdir"/usr/bin/hello-sym 29 | } 30 | 31 | sha512sums=" 32 | e80c0d471f7ec07708795b86127f0f7c968c49031f1e57cae200b5fbf2606e55fc4d56efb05a85c6f54dfe33e87d6789154cf15aee72ba0d216f08fb57926503 hello.c 33 | " 34 | -------------------------------------------------------------------------------- /tests/testrepo/pkg path with spaces/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | printf("hello world\n"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /tests/testrepo/pkg1/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname="pkg1" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | subpackages="$pkgname-dev $pkgname-doc" 10 | source="" 11 | builddir="$srcdir/pkg1-1.0" 12 | 13 | prepare() { 14 | mkdir -p "$builddir" 15 | } 16 | 17 | build() { 18 | mkdir -p usr/include usr/bin usr/share/man/man1 19 | touch usr/include/$pkgname.h 20 | touch usr/bin/$pkgname 21 | touch usr/share/man/man1/$pkgname.1 22 | } 23 | 24 | check() { 25 | true 26 | } 27 | 28 | package() { 29 | mkdir -p "$pkgdir" 30 | cp -R * "$pkgdir"/ 31 | } 32 | 33 | -------------------------------------------------------------------------------- /tests/testrepo/py3 foo and bar/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Test user 2 | pkgname=py3-foo-and-bar 3 | pkgver=1.0.0 4 | pkgrel=0 5 | pkgdesc="dummy package for test" 6 | url="https://alpinelinux.org" 7 | license="MIT" 8 | builddir="$srcdir" 9 | _sitedir=usr/lib/python3.9/site-packages 10 | 11 | package() { 12 | mkdir -p "$pkgdir"/$_sitedir/foo 13 | touch "$pkgdir"/$_sitedir/foo/__init__.py 14 | touch "$pkgdir"/$_sitedir/bar.py 15 | } 16 | -------------------------------------------------------------------------------- /tests/testrepo/py3-conflicting-python-versions/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Test user 2 | pkgname=py3-conflicting-python-versions 3 | pkgver=1.0.0 4 | pkgrel=0 5 | pkgdesc="dummy package for test" 6 | url="https://alpinelinux.org" 7 | license="MIT" 8 | builddir="$srcdir" 9 | 10 | package() { 11 | for pyver in 3.9 3.42; do 12 | local sitedir="usr/lib/python$pyver/site-packages" 13 | mkdir -p "$pkgdir"/$sitedir/foo 14 | touch "$pkgdir"/$sitedir/foo/__init__.py 15 | touch "$pkgdir"/$sitedir/bar.py 16 | done 17 | } 18 | -------------------------------------------------------------------------------- /tests/testrepo/setcap/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname=setcap 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc="Dummy test package that has an setcap binary but no setcap option" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | source="" 10 | 11 | prepare() { 12 | mkdir -p "$builddir" 13 | } 14 | 15 | build() { 16 | true 17 | } 18 | 19 | check() { 20 | true 21 | } 22 | 23 | package() { 24 | mkdir -p "$pkgdir/usr/bin" 25 | cat >"$pkgdir/usr/bin/foo" < 2 | pkgname=${TESTNAME-test-pkgname} 3 | pkgver="${TESTPKGVER-1.0}" 4 | pkgrel=0 5 | pkgdesc="Dummy subpackage arch" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | subpackages="$pkgname-$TESTSUBARCH:_sub:$TESTSUBARCH" 10 | options="!archcheck" 11 | 12 | check() { 13 | true 14 | } 15 | 16 | package() { 17 | mkdir -p "$pkgdir" 18 | } 19 | 20 | _sub() { 21 | mkdir -p "$subpkgdir" 22 | } 23 | -------------------------------------------------------------------------------- /tests/testrepo/test-licenses/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Olliver Schinagl 2 | pkgname="${TESTNAME-test-licenses}" 3 | pkgver="1.0" 4 | pkgrel=0 5 | pkgdesc='Dummy test package that has multi-line licenses' 6 | url='https://gitlab.alpinelinux.org/alpine/aports' 7 | arch='noarch' 8 | license='MIT AND 9 | (GPL-3.0-only OR 10 | 11 | GPL-3.0-or-later AND 12 | BSD-4-Clause) 13 | ' 14 | 15 | prepare() { 16 | mkdir -p "${builddir}" 17 | } 18 | 19 | build() { 20 | touch foo 21 | } 22 | 23 | check() { 24 | true 25 | } 26 | 27 | package() { 28 | mkdir -p "${pkgdir}" 29 | } 30 | -------------------------------------------------------------------------------- /tests/testrepo/test-pkgname/APKBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Natanael Copa 2 | pkgname=${TESTNAME-test-pkgname} 3 | pkgver="${TESTPKGVER-1.0}" 4 | pkgrel=0 5 | pkgdesc="Dummy test package that fails to build" 6 | url="https://gitlab.alpinelinux.org/alpine/aports" 7 | arch="noarch" 8 | license="MIT" 9 | provides="${TESTPROVIDES-provided}" 10 | subpackages="${TESTSUBNAME-$pkgname-sub}:_sub" 11 | depends="$TESTDEPENDS" 12 | makedepends="$TESTMAKEDEPENDS" 13 | 14 | prepare() { 15 | mkdir -p "$builddir" 16 | } 17 | 18 | build() { 19 | touch foo 20 | } 21 | 22 | check() { 23 | true 24 | } 25 | 26 | package() { 27 | mkdir -p "$pkgdir" 28 | cp -R * "$pkgdir"/ 29 | } 30 | 31 | _sub() { 32 | depends="$pkgname=${TESTDEPVER-$pkgver-r$pkgrel}" 33 | mkdir -p "$subpkgdir" 34 | } 35 | --------------------------------------------------------------------------------