Compare commits
107 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
e69cdca562 | |
|
|
5b9d922c84 | |
|
|
93eaefd383 | |
|
|
4cf32c5bc7 | |
|
|
6115fe4c44 | |
|
|
781108fbf6 | |
|
|
9c78876415 | |
|
|
a066c4447d | |
|
|
e42a069c4f | |
|
|
829b897456 | |
|
|
08e663916d | |
|
|
e15d2c3a1f | |
|
|
249d3b997f | |
|
|
bdbe351796 | |
|
|
45f78973e7 | |
|
|
db535710f7 | |
|
|
6bf2885139 | |
|
|
644e538311 | |
|
|
9c415246f2 | |
|
|
e8cd0920d7 | |
|
|
22d44e1c49 | |
|
|
ef63628054 | |
|
|
e0c3a1fc1a | |
|
|
e1113c24e0 | |
|
|
290fe0741c | |
|
|
b69b7e5787 | |
|
|
feecdfe87b | |
|
|
de7a214bf5 | |
|
|
c6069f5584 | |
|
|
583f7e4ba0 | |
|
|
aa55aaca93 | |
|
|
23e7e0f554 | |
|
|
dd58d6714e | |
|
|
c76917a4e1 | |
|
|
17bc375e0b | |
|
|
42808ab943 | |
|
|
8e54e5ca49 | |
|
|
8b24206e19 | |
|
|
f0e5b8abc0 | |
|
|
b328c15ff6 | |
|
|
010093698a | |
|
|
002b42e98e | |
|
|
bc75218f37 | |
|
|
fcee26e979 | |
|
|
9a77831902 | |
|
|
873bff3820 | |
|
|
1c3cfe741e | |
|
|
6025469d52 | |
|
|
fdfc384e71 | |
|
|
82ddba7a8c | |
|
|
7cc4aa7509 | |
|
|
207bd73577 | |
|
|
7ef007ef5f | |
|
|
3f044a426f | |
|
|
4beb98f193 | |
|
|
2c301c733d | |
|
|
b10350b913 | |
|
|
93ac15729b | |
|
|
08dc21b8f1 | |
|
|
f817f7a5da | |
|
|
f714f4b4f1 | |
|
|
28fea4c930 | |
|
|
b2f2fc6624 | |
|
|
e7e7449815 | |
|
|
862a6863cd | |
|
|
858d1c1419 | |
|
|
98cc060ede | |
|
|
512f4a9eb3 | |
|
|
8acb2f51d7 | |
|
|
468f455862 | |
|
|
e6b83c4788 | |
|
|
13a3c6992e | |
|
|
572cf390a7 | |
|
|
d30e641bb8 | |
|
|
ad4402f3bf | |
|
|
c326b39d95 | |
|
|
e66a359a10 | |
|
|
c028e71206 | |
|
|
0fb0d26152 | |
|
|
b852c59b02 | |
|
|
790f53c766 | |
|
|
d81a1ad1ac | |
|
|
fd06d93533 | |
|
|
e94f56c01e | |
|
|
843c729b16 | |
|
|
18e04a70e1 | |
|
|
e7903804af | |
|
|
6957220642 | |
|
|
bf0aa55655 | |
|
|
5092c5f659 | |
|
|
5960c8c4a7 | |
|
|
eb56972540 | |
|
|
20aa78c72c | |
|
|
ae8205261a | |
|
|
0cba81fbe4 | |
|
|
9d3d96a93d | |
|
|
86be3cc802 | |
|
|
13228bf566 | |
|
|
d0884e8903 | |
|
|
3b2b258020 | |
|
|
847ded9eba | |
|
|
c9d749a3a7 | |
|
|
49093c3533 | |
|
|
e0edc7e559 | |
|
|
b085edc49c | |
|
|
ad6b18a0aa | |
|
|
066b9b561a |
|
|
@ -10,9 +10,10 @@ jobs:
|
|||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
ruby-version: ['2.7', '3.0', '3.1']
|
||||
ruby-version: ['2.7', '3.0', '3.1', '3.4']
|
||||
steps:
|
||||
- run: |
|
||||
sudo apt-get update
|
||||
sudo apt install -y libarchive-tools lintian cpanminus
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ruby/setup-ruby@v1
|
||||
|
|
@ -20,6 +21,10 @@ jobs:
|
|||
ruby-version: ${{ matrix.ruby-version }}
|
||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||
- run: |
|
||||
bundle exec rspec
|
||||
if [ ! -z "$RUNNER_DEBUG" ] ; then
|
||||
DEBUG=1 bundle exec rspec -fd
|
||||
else
|
||||
bundle exec rspec
|
||||
fi
|
||||
env:
|
||||
SHELL: /usr/bin/bash
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
# https://blog.readthedocs.com/build-errors-docutils-0-18/
|
||||
version: 2
|
||||
|
||||
build:
|
||||
os: ubuntu-24.04
|
||||
tools:
|
||||
python: "3.13"
|
||||
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
|
||||
python:
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
|
|
|||
|
|
@ -1,6 +1,36 @@
|
|||
Release Notes and Change Log
|
||||
============================
|
||||
|
||||
1.17.0 (October 2, 2025)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* python: Support modern Python project features: pyproject.toml, wheels, etc. Now, any project that can be built or installed with ``pip`` can be packaged by fpm. Previously, fpm relied on a long-deprecated features in setup.py to see a python project's metadata such as name, version, and dependencies. Fpm now uses python's package tools to identify the project's name, version, dependencies, and other information. (`#2104`_, `#2105`_, `#2040`_, `#1982`_, `#2029`_; Jordan Sissel, cwegener, amdei, gmabey)
|
||||
* dir: When copying files, only use hardlinks if the original files were also hardlinks. (`#2103`_, `#2102`_; Michael Telatynski, Matthew Rathbone, Jordan Sissel). :w
|
||||
Related: https://github.com/electron-userland/electron-builder/issues/5721
|
||||
* deb: bug fix: when a file given with ``--config-files <path>`` copied into the package, fpm was forgetting to mark the file as being a config file in the package, aka Debian "conffiles" (`#2027`_, `#1823`_; Alexandr Zarubkin, Kientz Arnaud)
|
||||
* pacman: Now can build packages with aarch64 and arm7hf architecture (`#2017`_; Markson Hon)
|
||||
* rpm: Paths with '{' and '}' characters can now be included in rpms (`#2088`_ `#2087`_; Jordan Sissel, Manish2481983)
|
||||
* docs: Updated urls which pointed at rpm documentation (`#2092`_, `#2011`_, `#2054`_; André Kelpe, Natanael Arndt)
|
||||
* Ruby 3.4.0 no longer gives warnings related to `ostruct` (`#2106`_, also `#2104`_ and `#2103`_; Jordan Sissel)
|
||||
|
||||
1.16.0 (December 8, 2024)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* deb: Add support for zstd compression (`#2009`_, `#2084`_; Ștefan Rusu)
|
||||
* deb: Add compression level setting, ``--deb-compression-level`` (`#2036`_; Hugo Beauzée-Luyssen)
|
||||
* rpm: Generate an empty rpm changelog if none is given. This should help cases where ``rpmlint`` would complain about missing a changelog entry in the rpm. (`#2041`_; Gordon Bleux)
|
||||
* deb: When converting from an rpm, remove package information that is not valid on Debian systems. (`#2053`_, `#1627`; Jordan Stopford, Jamesits)
|
||||
* python: Fix bug when PYTHONPATH has spaces in it (`#2062`_; Kristof Willaert)
|
||||
* deb: You can now choose a different systemd directory with ``--deb-systemd-path`` (`#2063`_; Reinier Schoof)
|
||||
* freebsd: OS version can now be specified with ``--freebsd-osversion``: (`#2064`_; David Newhall II)
|
||||
* freebsd: Improve the 'architecture' value used by fpm to generate freebsd packages (`#2064`_, `#1880`_; David Newhall II, Matthew R Kasun)
|
||||
* deb: Timer units can be given to ``--deb-systemd`` now (`#2065`_, `#1978`_; phillipp, Robert Schneider)
|
||||
* rpm: When converting cpan packages, use newer ``perl-interpreter`` dependency name. To use the old dependency name ``perl``, use the flag ``--rpm-old-perl-dependency-name`` (`#2066`_, `#2085`_; Kevin Duret, Nicholas Hubbard, William N. Braswell, Jr., Jordan Sissel))
|
||||
* Some errors now correctly print just an error message instead of dumping a ruby stack trace (`#2067`_; Jordan Sissel)
|
||||
* python: Support modules which download as zip files (`#2068`_, `#2074`_, `#2072`_; Matt Ezell, hussainbani, hbani)
|
||||
* rpm: Fix rpm build failures on Fedora 41 (`#2082`_, `#2076`_; Wayne Heaney, Antheas Kapenekakis, Romain Geissler)
|
||||
|
||||
|
||||
1.15.1 (January 31, 2023)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* Ruby 3.2.0 now supported. This fixes error 'undefined method exists? for File' '(`#1981`_, `#1988`_; Nicholas Hubbard, romulasry)
|
||||
|
|
|
|||
4
Makefile
4
Makefile
|
|
@ -53,9 +53,9 @@ clean:
|
|||
publish-docs:
|
||||
$(MAKE) -C docs publish
|
||||
|
||||
release-prep:
|
||||
release-prep: package
|
||||
rm -f docs/changelog_links.rst docs/cli-reference.rst
|
||||
make -C docs changelog_links.rst cli-reference.rst package-type-cli
|
||||
make -C docs build package-type-cli
|
||||
|
||||
# Testing in docker.
|
||||
# The dot file is a sentinal file that will built a docker image, and tag it.
|
||||
|
|
|
|||
53
NOTES.md
53
NOTES.md
|
|
@ -1,53 +0,0 @@
|
|||
|
||||
# Debian notes
|
||||
|
||||
## C libraries
|
||||
|
||||
Linux seems to require 'ldconfig' runs after shared libraries are installed. I
|
||||
haven't bothered digging into why, but many debian C library packages run
|
||||
ldconfig as a postinstall step.
|
||||
|
||||
I'd like to avoid postinstall actions, so this needs research to see if this is
|
||||
possible.
|
||||
|
||||
## Ruby
|
||||
|
||||
rubygems on Debian/Ubuntu is not very recent in most cases, and some gems have
|
||||
a requirement of rubygems >= a version you have available.
|
||||
|
||||
Further, debian blocks 'gem update --system' which you can get around by doing:
|
||||
|
||||
% gem install rubygems-update
|
||||
% ruby /var/lib/gems/1.8/gems/rubygems-update-1.3.1/bin/update_rubygems
|
||||
|
||||
I recommend packaging 'rubygems-update' (fpm -s gem -t deb rubygems-update) and
|
||||
possibly running the update_rubygems as a postinstall, even though I don't like
|
||||
postinstalls. I haven't looked yet to see what is required to mimic (if
|
||||
possible) the actions of that script simply in a tarball.
|
||||
|
||||
## Python
|
||||
|
||||
https://www.debian.org/doc/packaging-manuals/python-policy/ap-packaging_tools.html
|
||||
|
||||
Debian python packages all rely on some form of python-central or
|
||||
python-support (different tools that do similar/same things? I don't know)
|
||||
|
||||
As I found, disabling postinst scripts in Debian causes Python to stop working.
|
||||
The postinst scripts generally look like this:
|
||||
|
||||
if which update-python-modules >/dev/null 2>&1; then
|
||||
update-python-modules SOMEPACKAGENAME.public
|
||||
fi
|
||||
|
||||
I don't believe in postinst scripts, and I also feel like requiring a
|
||||
postinstall step to make a python module work is quite silly - though I'm sure
|
||||
(I hope) Debian had good reason.
|
||||
|
||||
So, I'm going to try working on a howto for recommended ways to build python
|
||||
packages with fpm in debian. It will likely require a one-time addition to
|
||||
site.py (/usr/lib/python2.6/site.py) or some other PYTHONPATH hackery, though
|
||||
I don't know just yet.
|
||||
|
||||
It will also require special setup.py invocations as Debian has patched distutils to
|
||||
install python packages, by default, to a place that requires again the
|
||||
python-central/support tools to run to make them work.
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
fpm
|
||||
===
|
||||
|
||||
|Chat| |Gem|
|
||||
|Gem|
|
||||
|
||||
The goal of fpm is to make it easy and quick to build packages such as rpms,
|
||||
debs, OSX packages, etc.
|
||||
|
|
@ -97,7 +97,5 @@ Targets:
|
|||
|
||||
.. include: docs/contributing
|
||||
|
||||
.. |Chat| image:: https://img.shields.io/badge/irc-%23fpm%20on%20freenode-brightgreen.svg
|
||||
:target: https://webchat.freenode.net/?channels=fpm
|
||||
.. |Gem| image:: https://img.shields.io/gem/v/fpm.svg
|
||||
:target: https://rubygems.org/gems/fpm
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
FROM debian:latest
|
||||
RUN apt-get update
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3-pip
|
||||
RUN pip3 install Sphinx
|
||||
RUN apt-get install -y python3-sphinx #pip3 install Sphinx
|
||||
#==1.8
|
||||
RUN pip3 install sphinx_rtd_theme
|
||||
RUN pip3 install alabaster
|
||||
RUN pip3 install sphinx-autobuild
|
||||
RUN apt-get install -y python3-sphinx python3-sphinx-rtd-theme python3-sphinx-autobuild
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
|
|
|
|||
|
|
@ -32,16 +32,16 @@ packages/cli/%.rst: ../lib/fpm/package/%.rb packages/cli generate-cli-reference.
|
|||
ruby -I ../lib generate-cli-reference.rb $* > $@
|
||||
|
||||
|
||||
.PHONY: podman-prep
|
||||
podman-prep: Dockerfile
|
||||
@podman images fpm-sphinx | grep -q '^fpm-sphinx ' \
|
||||
|| podman build -t $(IMAGE) .
|
||||
.PHONY: docker-prep
|
||||
docker-prep: Dockerfile
|
||||
@docker images fpm-sphinx | grep -q '^fpm-sphinx ' \
|
||||
|| docker build -t $(IMAGE) .
|
||||
|
||||
.PHONY: build
|
||||
build: $(GENERATED_FILES) | podman-prep
|
||||
podman run -it -v $$PWD/../:/project:z $(IMAGE) sh -xc 'make -C /project/docs html && chown -R 1000:1000 /project/docs'
|
||||
build: $(GENERATED_FILES) | docker-prep package-type-cli
|
||||
docker run -it -v $$PWD/../:/project:z $(IMAGE) sh -xc 'make -C /project/docs html && chown -R 1000:1000 /project/docs'
|
||||
|
||||
|
||||
.PHONY: build
|
||||
view: $(GENERATED_FILES) | podman-prep
|
||||
podman run -p 127.0.0.1:8000:8000 -it -v $$PWD/../:/project:z $(IMAGE) sh -xc 'make -C /project/docs livehtml'
|
||||
view: $(GENERATED_FILES) | docker-prep
|
||||
docker run -p 127.0.0.1:8000:8000 -it -v $$PWD/../:/project:z $(IMAGE) sh -xc 'make -C /project/docs livehtml'
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
.. _#1523: https://github.com/jordansissel/fpm/issues/1523
|
||||
.. _#1528: https://github.com/jordansissel/fpm/issues/1528
|
||||
.. _#1592: https://github.com/jordansissel/fpm/issues/1592
|
||||
.. _#1627: https://github.com/jordansissel/fpm/issues/1627
|
||||
.. _#1636: https://github.com/jordansissel/fpm/issues/1636
|
||||
.. _#1642: https://github.com/jordansissel/fpm/issues/1642
|
||||
.. _#1667: https://github.com/jordansissel/fpm/issues/1667
|
||||
|
|
@ -145,6 +146,7 @@
|
|||
.. _#1818: https://github.com/jordansissel/fpm/issues/1818
|
||||
.. _#1820: https://github.com/jordansissel/fpm/issues/1820
|
||||
.. _#1821: https://github.com/jordansissel/fpm/issues/1821
|
||||
.. _#1823: https://github.com/jordansissel/fpm/issues/1823
|
||||
.. _#1825: https://github.com/jordansissel/fpm/issues/1825
|
||||
.. _#1827: https://github.com/jordansissel/fpm/issues/1827
|
||||
.. _#1829: https://github.com/jordansissel/fpm/issues/1829
|
||||
|
|
@ -170,6 +172,7 @@
|
|||
.. _#1877: https://github.com/jordansissel/fpm/issues/1877
|
||||
.. _#1879: https://github.com/jordansissel/fpm/issues/1879
|
||||
.. _#187: https://github.com/jordansissel/fpm/issues/187
|
||||
.. _#1880: https://github.com/jordansissel/fpm/issues/1880
|
||||
.. _#1882: https://github.com/jordansissel/fpm/issues/1882
|
||||
.. _#1884: https://github.com/jordansissel/fpm/issues/1884
|
||||
.. _#1886: https://github.com/jordansissel/fpm/issues/1886
|
||||
|
|
@ -205,15 +208,48 @@
|
|||
.. _#1955: https://github.com/jordansissel/fpm/issues/1955
|
||||
.. _#1959: https://github.com/jordansissel/fpm/issues/1959
|
||||
.. _#196: https://github.com/jordansissel/fpm/issues/196
|
||||
.. _#1978: https://github.com/jordansissel/fpm/issues/1978
|
||||
.. _#1981: https://github.com/jordansissel/fpm/issues/1981
|
||||
.. _#1982: https://github.com/jordansissel/fpm/issues/1982
|
||||
.. _#1988: https://github.com/jordansissel/fpm/issues/1988
|
||||
.. _#198: https://github.com/jordansissel/fpm/issues/198
|
||||
.. _#2009: https://github.com/jordansissel/fpm/issues/2009
|
||||
.. _#2011: https://github.com/jordansissel/fpm/issues/2011
|
||||
.. _#2017: https://github.com/jordansissel/fpm/issues/2017
|
||||
.. _#2027: https://github.com/jordansissel/fpm/issues/2027
|
||||
.. _#2029: https://github.com/jordansissel/fpm/issues/2029
|
||||
.. _#202: https://github.com/jordansissel/fpm/issues/202
|
||||
.. _#2036: https://github.com/jordansissel/fpm/issues/2036
|
||||
.. _#2040: https://github.com/jordansissel/fpm/issues/2040
|
||||
.. _#2041: https://github.com/jordansissel/fpm/issues/2041
|
||||
.. _#204: https://github.com/jordansissel/fpm/issues/204
|
||||
.. _#2053: https://github.com/jordansissel/fpm/issues/2053
|
||||
.. _#2054: https://github.com/jordansissel/fpm/issues/2054
|
||||
.. _#205: https://github.com/jordansissel/fpm/issues/205
|
||||
.. _#2062: https://github.com/jordansissel/fpm/issues/2062
|
||||
.. _#2063: https://github.com/jordansissel/fpm/issues/2063
|
||||
.. _#2064: https://github.com/jordansissel/fpm/issues/2064
|
||||
.. _#2065: https://github.com/jordansissel/fpm/issues/2065
|
||||
.. _#2066: https://github.com/jordansissel/fpm/issues/2066
|
||||
.. _#2067: https://github.com/jordansissel/fpm/issues/2067
|
||||
.. _#2068: https://github.com/jordansissel/fpm/issues/2068
|
||||
.. _#206: https://github.com/jordansissel/fpm/issues/206
|
||||
.. _#2072: https://github.com/jordansissel/fpm/issues/2072
|
||||
.. _#2074: https://github.com/jordansissel/fpm/issues/2074
|
||||
.. _#2076: https://github.com/jordansissel/fpm/issues/2076
|
||||
.. _#207: https://github.com/jordansissel/fpm/issues/207
|
||||
.. _#2082: https://github.com/jordansissel/fpm/issues/2082
|
||||
.. _#2084: https://github.com/jordansissel/fpm/issues/2084
|
||||
.. _#2085: https://github.com/jordansissel/fpm/issues/2085
|
||||
.. _#2087: https://github.com/jordansissel/fpm/issues/2087
|
||||
.. _#2088: https://github.com/jordansissel/fpm/issues/2088
|
||||
.. _#208: https://github.com/jordansissel/fpm/issues/208
|
||||
.. _#2092: https://github.com/jordansissel/fpm/issues/2092
|
||||
.. _#2102: https://github.com/jordansissel/fpm/issues/2102
|
||||
.. _#2103: https://github.com/jordansissel/fpm/issues/2103
|
||||
.. _#2104: https://github.com/jordansissel/fpm/issues/2104
|
||||
.. _#2105: https://github.com/jordansissel/fpm/issues/2105
|
||||
.. _#2106: https://github.com/jordansissel/fpm/issues/2106
|
||||
.. _#212: https://github.com/jordansissel/fpm/issues/212
|
||||
.. _#213: https://github.com/jordansissel/fpm/issues/213
|
||||
.. _#215: https://github.com/jordansissel/fpm/issues/215
|
||||
|
|
|
|||
|
|
@ -84,144 +84,6 @@ General Options
|
|||
* ``--conflicts CONFLICTS``
|
||||
- Other packages/versions this package conflicts with. This flag can be specified multiple times.
|
||||
|
||||
* ``--cpan-cpanm-bin CPANM_EXECUTABLE``
|
||||
- (cpan only) The path to the cpanm executable you wish to run.
|
||||
|
||||
* ``--[no-]cpan-cpanm-force``
|
||||
- (cpan only) Pass the --force parameter to cpanm
|
||||
|
||||
* ``--cpan-mirror CPAN_MIRROR``
|
||||
- (cpan only) The CPAN mirror to use instead of the default.
|
||||
|
||||
* ``--[no-]cpan-mirror-only``
|
||||
- (cpan only) Only use the specified mirror for metadata.
|
||||
|
||||
* ``--cpan-package-name-prefix NAME_PREFIX``
|
||||
- (cpan only) Name to prefix the package name with.
|
||||
|
||||
* ``--cpan-perl-bin PERL_EXECUTABLE``
|
||||
- (cpan only) The path to the perl executable you wish to run.
|
||||
|
||||
* ``--cpan-perl-lib-path PERL_LIB_PATH``
|
||||
- (cpan only) Path of target Perl Libraries
|
||||
|
||||
* ``--[no-]cpan-sandbox-non-core``
|
||||
- (cpan only) Sandbox all non-core modules, even if they're already installed
|
||||
|
||||
* ``--[no-]cpan-test``
|
||||
- (cpan only) Run the tests before packaging?
|
||||
|
||||
* ``--[no-]cpan-verbose``
|
||||
- (cpan only) Produce verbose output from cpanm?
|
||||
|
||||
* ``--deb-activate EVENT``
|
||||
- (deb only) Package activates EVENT trigger
|
||||
|
||||
* ``--deb-activate-noawait EVENT``
|
||||
- (deb only) Package activates EVENT trigger
|
||||
|
||||
* ``--deb-after-purge FILE``
|
||||
- (deb only) A script to be run after package removal to purge remaining (config) files (a.k.a. postrm purge within apt-get purge)
|
||||
|
||||
* ``--[no-]deb-auto-config-files``
|
||||
- (deb only) Init script and default configuration files will be labeled as configuration files for Debian packages.
|
||||
|
||||
* ``--deb-build-depends DEPENDENCY``
|
||||
- (deb only) Add DEPENDENCY as a Build-Depends
|
||||
|
||||
* ``--deb-changelog FILEPATH``
|
||||
- (deb only) Add FILEPATH as debian changelog
|
||||
|
||||
* ``--deb-compression COMPRESSION``
|
||||
- (deb only) The compression type to use, must be one of gz, bzip2, xz, none.
|
||||
|
||||
* ``--deb-config SCRIPTPATH``
|
||||
- (deb only) Add SCRIPTPATH as debconf config file.
|
||||
|
||||
* ``--deb-custom-control FILEPATH``
|
||||
- (deb only) Custom version of the Debian control file.
|
||||
|
||||
* ``--deb-default FILEPATH``
|
||||
- (deb only) Add FILEPATH as /etc/default configuration
|
||||
|
||||
* ``--deb-dist DIST-TAG``
|
||||
- (deb only) Set the deb distribution.
|
||||
|
||||
* ``--deb-field 'FIELD: VALUE'``
|
||||
- (deb only) Add custom field to the control file
|
||||
|
||||
* ``--[no-]deb-generate-changes``
|
||||
- (deb only) Generate PACKAGENAME.changes file.
|
||||
|
||||
* ``--deb-group GROUP``
|
||||
- (deb only) The group owner of files in this package
|
||||
|
||||
* ``--[no-]deb-ignore-iteration-in-dependencies``
|
||||
- (deb only) For '=' (equal) dependencies, allow iterations on the specified version. Default is to be specific. This option allows the same version of a package but any iteration is permitted
|
||||
|
||||
* ``--deb-init FILEPATH``
|
||||
- (deb only) Add FILEPATH as an init script
|
||||
|
||||
* ``--deb-installed-size KILOBYTES``
|
||||
- (deb only) The installed size, in kilobytes. If omitted, this will be calculated automatically
|
||||
|
||||
* ``--deb-interest EVENT``
|
||||
- (deb only) Package is interested in EVENT trigger
|
||||
|
||||
* ``--deb-interest-noawait EVENT``
|
||||
- (deb only) Package is interested in EVENT trigger without awaiting
|
||||
|
||||
* ``--[no-]deb-maintainerscripts-force-errorchecks``
|
||||
- (deb only) Activate errexit shell option according to lintian. https://lintian.debian.org/tags/maintainer-script-ignores-errors.html
|
||||
|
||||
* ``--deb-meta-file FILEPATH``
|
||||
- (deb only) Add FILEPATH to DEBIAN directory
|
||||
|
||||
* ``--[no-]deb-no-default-config-files``
|
||||
- (deb only) Do not add all files in /etc as configuration files by default for Debian packages.
|
||||
|
||||
* ``--deb-pre-depends DEPENDENCY``
|
||||
- (deb only) Add DEPENDENCY as a Pre-Depends
|
||||
|
||||
* ``--deb-priority PRIORITY``
|
||||
- (deb only) The debian package 'priority' value.
|
||||
|
||||
* ``--deb-recommends PACKAGE``
|
||||
- (deb only) Add PACKAGE to Recommends
|
||||
|
||||
* ``--deb-shlibs SHLIBS``
|
||||
- (deb only) Include control/shlibs content. This flag expects a string that is used as the contents of the shlibs file. See the following url for a description of this file and its format: http://www.debian.org/doc/debian-policy/ch-sharedlibs.html#s-shlibs
|
||||
|
||||
* ``--deb-suggests PACKAGE``
|
||||
- (deb only) Add PACKAGE to Suggests
|
||||
|
||||
* ``--deb-systemd FILEPATH``
|
||||
- (deb only) Add FILEPATH as a systemd script
|
||||
|
||||
* ``--[no-]deb-systemd-auto-start``
|
||||
- (deb only) Start service after install or upgrade
|
||||
|
||||
* ``--[no-]deb-systemd-enable``
|
||||
- (deb only) Enable service on install or upgrade
|
||||
|
||||
* ``--[no-]deb-systemd-restart-after-upgrade``
|
||||
- (deb only) Restart service after upgrade
|
||||
|
||||
* ``--deb-templates FILEPATH``
|
||||
- (deb only) Add FILEPATH as debconf templates file.
|
||||
|
||||
* ``--deb-upstart FILEPATH``
|
||||
- (deb only) Add FILEPATH as an upstart script
|
||||
|
||||
* ``--deb-upstream-changelog FILEPATH``
|
||||
- (deb only) Add FILEPATH as upstream changelog
|
||||
|
||||
* ``--[no-]deb-use-file-permissions``
|
||||
- (deb only) Use existing file permissions when defining ownership and modes
|
||||
|
||||
* ``--deb-user USER``
|
||||
- (deb only) The owner of files in this package
|
||||
|
||||
* ``--debug``
|
||||
- Enable debug output
|
||||
|
||||
|
|
@ -243,54 +105,6 @@ General Options
|
|||
* ``--fpm-options-file FPM_OPTIONS_FILE``
|
||||
- A file that contains additional fpm options. Any fpm flag format is valid in this file. This can be useful on build servers where you want to use a common configuration or inject other parameters from a file instead of from a command-line flag..
|
||||
|
||||
* ``--freebsd-origin ABI``
|
||||
- (freebsd only) Sets the FreeBSD 'origin' pkg field
|
||||
|
||||
* ``--gem-bin-path DIRECTORY``
|
||||
- (gem only) The directory to install gem executables
|
||||
|
||||
* ``--gem-disable-dependency gem_name``
|
||||
- (gem only) The gem name to remove from dependency list
|
||||
|
||||
* ``--[no-]gem-embed-dependencies``
|
||||
- (gem only) Should the gem dependencies be installed?
|
||||
|
||||
* ``--[no-]gem-env-shebang``
|
||||
- (gem only) Should the target package have the shebang rewritten to use env?
|
||||
|
||||
* ``--[no-]gem-fix-dependencies``
|
||||
- (gem only) Should the package dependencies be prefixed?
|
||||
|
||||
* ``--[no-]gem-fix-name``
|
||||
- (gem only) Should the target package name be prefixed?
|
||||
|
||||
* ``--gem-gem PATH_TO_GEM``
|
||||
- (gem only) The path to the 'gem' tool (defaults to 'gem' and searches your $PATH)
|
||||
|
||||
* ``--gem-git-branch GIT_BRANCH``
|
||||
- (gem only) When using a git repo as the source of the gem instead of rubygems.org, use this git branch.
|
||||
|
||||
* ``--gem-git-repo GIT_REPO``
|
||||
- (gem only) Use this git repo address as the source of the gem instead of rubygems.org.
|
||||
|
||||
* ``--gem-package-name-prefix PREFIX``
|
||||
- (gem only) Name to prefix the package name with.
|
||||
|
||||
* ``--gem-package-prefix NAMEPREFIX``
|
||||
- (gem only) (DEPRECATED, use --package-name-prefix) Name to prefix the package name with.
|
||||
|
||||
* ``--[no-]gem-prerelease``
|
||||
- (gem only) Allow prerelease versions of a gem
|
||||
|
||||
* ``--gem-shebang SHEBANG``
|
||||
- (gem only) Replace the shebang in the executables in the bin path with a custom string
|
||||
|
||||
* ``--gem-stagingdir STAGINGDIR``
|
||||
- (gem only) The directory where fpm installs the gem temporarily before conversion. Normally a random subdirectory of workdir.
|
||||
|
||||
* ``--[no-]gem-version-bins``
|
||||
- (gem only) Append the version to the bins
|
||||
|
||||
* ``--inputs INPUTS_PATH``
|
||||
- The path to a file containing a newline-separated list of files and dirs to use as input.
|
||||
|
||||
|
|
@ -309,93 +123,6 @@ General Options
|
|||
* ``--no-depends``
|
||||
- Do not list any dependencies in this package
|
||||
|
||||
* ``--npm-bin NPM_EXECUTABLE``
|
||||
- (npm only) The path to the npm executable you wish to run.
|
||||
|
||||
* ``--npm-package-name-prefix PREFIX``
|
||||
- (npm only) Name to prefix the package name with.
|
||||
|
||||
* ``--npm-registry NPM_REGISTRY``
|
||||
- (npm only) The npm registry to use instead of the default.
|
||||
|
||||
* ``--osxpkg-dont-obsolete DONT_OBSOLETE_PATH``
|
||||
- (osxpkg only) A file path for which to 'dont-obsolete' in the built PackageInfo. Can be specified multiple times.
|
||||
|
||||
* ``--osxpkg-identifier-prefix IDENTIFIER_PREFIX``
|
||||
- (osxpkg only) Reverse domain prefix prepended to package identifier, ie. 'org.great.my'. If this is omitted, the identifer will be the package name.
|
||||
|
||||
* ``--osxpkg-ownership OWNERSHIP``
|
||||
- (osxpkg only) --ownership option passed to pkgbuild. Defaults to 'recommended'. See pkgbuild(1).
|
||||
|
||||
* ``--[no-]osxpkg-payload-free``
|
||||
- (osxpkg only) Define no payload, assumes use of script options.
|
||||
|
||||
* ``--osxpkg-postinstall-action POSTINSTALL_ACTION``
|
||||
- (osxpkg only) Post-install action provided in package metadata. Optionally one of 'logout', 'restart', 'shutdown'.
|
||||
|
||||
* ``--p5p-group GROUP``
|
||||
- (p5p only) Set the group to GROUP in the prototype file.
|
||||
|
||||
* ``--[no-]p5p-lint``
|
||||
- (p5p only) Check manifest with pkglint
|
||||
|
||||
* ``--p5p-publisher PUBLISHER``
|
||||
- (p5p only) Set the publisher name for the repository
|
||||
|
||||
* ``--p5p-user USER``
|
||||
- (p5p only) Set the user to USER in the prototype files.
|
||||
|
||||
* ``--[no-]p5p-validate``
|
||||
- (p5p only) Validate with pkg install
|
||||
|
||||
* ``--p5p-zonetype ZONETYPE``
|
||||
- (p5p only) Set the allowed zone types (global, nonglobal, both)
|
||||
|
||||
* ``--pacman-compression COMPRESSION``
|
||||
- (pacman only) The compression type to use, must be one of gz, bzip2, xz, zstd, none.
|
||||
|
||||
* ``--pacman-group GROUP``
|
||||
- (pacman only) The group owner of files in this package
|
||||
|
||||
* ``--pacman-optional-depends PACKAGE``
|
||||
- (pacman only) Add an optional dependency to the pacman package.
|
||||
|
||||
* ``--[no-]pacman-use-file-permissions``
|
||||
- (pacman only) Use existing file permissions when defining ownership and modes
|
||||
|
||||
* ``--pacman-user USER``
|
||||
- (pacman only) The owner of files in this package
|
||||
|
||||
* ``--pear-bin-dir BIN_DIR``
|
||||
- (pear only) Directory to put binaries in
|
||||
|
||||
* ``--pear-channel CHANNEL_URL``
|
||||
- (pear only) The pear channel url to use instead of the default.
|
||||
|
||||
* ``--[no-]pear-channel-update``
|
||||
- (pear only) call 'pear channel-update' prior to installation
|
||||
|
||||
* ``--pear-data-dir DATA_DIR``
|
||||
- (pear only) Specify php dir relative to prefix if differs from pear default (pear/data)
|
||||
|
||||
* ``--pear-package-name-prefix PREFIX``
|
||||
- (pear only) Name prefix for pear package
|
||||
|
||||
* ``--pear-php-bin PHP_BIN``
|
||||
- (pear only) Specify php executable path if differs from the os used for packaging
|
||||
|
||||
* ``--pear-php-dir PHP_DIR``
|
||||
- (pear only) Specify php dir relative to prefix if differs from pear default (pear/php)
|
||||
|
||||
* ``--pleaserun-chdir CHDIR``
|
||||
- (pleaserun only) The working directory used by the service
|
||||
|
||||
* ``--pleaserun-name SERVICE_NAME``
|
||||
- (pleaserun only) The name of the service you are creating
|
||||
|
||||
* ``--pleaserun-user USER``
|
||||
- (pleaserun only) The user to use for executing this program.
|
||||
|
||||
* ``--post-install FILE``
|
||||
- (DEPRECATED, use --after-install) A script to be run after package installation
|
||||
|
||||
|
|
@ -414,186 +141,9 @@ General Options
|
|||
* ``--provides PROVIDES``
|
||||
- What this package provides (usually a name). This flag can be specified multiple times.
|
||||
|
||||
* ``--python-bin PYTHON_EXECUTABLE``
|
||||
- (python only) The path to the python executable you wish to run.
|
||||
|
||||
* ``--[no-]python-dependencies``
|
||||
- (python only) Include requirements defined in setup.py as dependencies.
|
||||
|
||||
* ``--python-disable-dependency python_package_name``
|
||||
- (python only) The python package name to remove from dependency list
|
||||
|
||||
* ``--[no-]python-downcase-dependencies``
|
||||
- (python only) Should the package dependencies be in lowercase?
|
||||
|
||||
* ``--[no-]python-downcase-name``
|
||||
- (python only) Should the target package name be in lowercase?
|
||||
|
||||
* ``--python-easyinstall EASYINSTALL_EXECUTABLE``
|
||||
- (python only) The path to the easy_install executable tool
|
||||
|
||||
* ``--[no-]python-fix-dependencies``
|
||||
- (python only) Should the package dependencies be prefixed?
|
||||
|
||||
* ``--[no-]python-fix-name``
|
||||
- (python only) Should the target package name be prefixed?
|
||||
|
||||
* ``--python-install-bin BIN_PATH``
|
||||
- (python only) The path to where python scripts should be installed to.
|
||||
|
||||
* ``--python-install-data DATA_PATH``
|
||||
- (python only) The path to where data should be installed to. This is equivalent to 'python setup.py --install-data DATA_PATH
|
||||
|
||||
* ``--python-install-lib LIB_PATH``
|
||||
- (python only) The path to where python libs should be installed to (default depends on your python installation). Want to find out what your target platform is using? Run this: python -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()'
|
||||
|
||||
* ``--[no-]python-internal-pip``
|
||||
- (python only) Use the pip module within python to install modules - aka 'python -m pip'. This is the recommended usage since Python 3.4 (2014) instead of invoking the 'pip' script
|
||||
|
||||
* ``--[no-]python-obey-requirements-txt``
|
||||
- (python only) Use a requirements.txt file in the top-level directory of the python package for dependency detection.
|
||||
|
||||
* ``--python-package-name-prefix PREFIX``
|
||||
- (python only) Name to prefix the package name with.
|
||||
|
||||
* ``--python-package-prefix NAMEPREFIX``
|
||||
- (python only) (DEPRECATED, use --package-name-prefix) Name to prefix the package name with.
|
||||
|
||||
* ``--python-pip PIP_EXECUTABLE``
|
||||
- (python only) The path to the pip executable tool. If not specified, easy_install is used instead
|
||||
|
||||
* ``--python-pypi PYPI_URL``
|
||||
- (python only) PyPi Server uri for retrieving packages.
|
||||
|
||||
* ``--python-scripts-executable PYTHON_EXECUTABLE``
|
||||
- (python only) Set custom python interpreter in installing scripts. By default distutils will replace python interpreter in installing scripts (specified by shebang) with current python interpreter (sys.executable). This option is equivalent to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments to 'setup.py install' command.
|
||||
|
||||
* ``--python-setup-py-arguments setup_py_argument``
|
||||
- (python only) Arbitrary argument(s) to be passed to setup.py
|
||||
|
||||
* ``--python-trusted-host PYPI_TRUSTED``
|
||||
- (python only) Mark this host or host:port pair as trusted for pip
|
||||
|
||||
* ``--replaces REPLACES``
|
||||
- Other packages/versions this package replaces. Equivalent of rpm's 'Obsoletes'. This flag can be specified multiple times.
|
||||
|
||||
* ``--rpm-attr ATTRFILE``
|
||||
- (rpm only) Set the attribute for a file (%attr), e.g. --rpm-attr 750,user1,group1:/some/file
|
||||
|
||||
* ``--[no-]rpm-auto-add-directories``
|
||||
- (rpm only) Auto add directories not part of filesystem
|
||||
|
||||
* ``--rpm-auto-add-exclude-directories DIRECTORIES``
|
||||
- (rpm only) Additional directories ignored by '--rpm-auto-add-directories' flag
|
||||
|
||||
* ``--[no-]rpm-autoprov``
|
||||
- (rpm only) Enable RPM's AutoProv option
|
||||
|
||||
* ``--[no-]rpm-autoreq``
|
||||
- (rpm only) Enable RPM's AutoReq option
|
||||
|
||||
* ``--[no-]rpm-autoreqprov``
|
||||
- (rpm only) Enable RPM's AutoReqProv option
|
||||
|
||||
* ``--rpm-changelog FILEPATH``
|
||||
- (rpm only) Add changelog from FILEPATH contents
|
||||
|
||||
* ``--rpm-compression none|xz|xzmt|gzip|bzip2``
|
||||
- (rpm only) Select a compression method. gzip works on the most platforms.
|
||||
|
||||
* ``--rpm-compression-level [0-9]``
|
||||
- (rpm only) Select a compression level. 0 is store-only. 9 is max compression.
|
||||
|
||||
* ``--rpm-defattrdir ATTR``
|
||||
- (rpm only) Set the default dir mode (%defattr).
|
||||
|
||||
* ``--rpm-defattrfile ATTR``
|
||||
- (rpm only) Set the default file mode (%defattr).
|
||||
|
||||
* ``--rpm-digest md5|sha1|sha256|sha384|sha512``
|
||||
- (rpm only) Select a digest algorithm. md5 works on the most platforms.
|
||||
|
||||
* ``--rpm-dist DIST-TAG``
|
||||
- (rpm only) Set the rpm distribution.
|
||||
|
||||
* ``--rpm-filter-from-provides REGEX``
|
||||
- (rpm only) Set %filter_from_provides to the supplied REGEX.
|
||||
|
||||
* ``--rpm-filter-from-requires REGEX``
|
||||
- (rpm only) Set %filter_from_requires to the supplied REGEX.
|
||||
|
||||
* ``--rpm-group GROUP``
|
||||
- (rpm only) Set the group to GROUP in the %files section. Overrides the group when used with use-file-permissions setting.
|
||||
|
||||
* ``--[no-]rpm-ignore-iteration-in-dependencies``
|
||||
- (rpm only) For '=' (equal) dependencies, allow iterations on the specified version. Default is to be specific. This option allows the same version of a package but any iteration is permitted
|
||||
|
||||
* ``--rpm-init FILEPATH``
|
||||
- (rpm only) Add FILEPATH as an init script
|
||||
|
||||
* ``--[no-]rpm-macro-expansion``
|
||||
- (rpm only) install-time macro expansion in %pre %post %preun %postun scripts (see: https://rpm.org/user_doc/scriptlet_expansion.html)
|
||||
|
||||
* ``--rpm-os OS``
|
||||
- (rpm only) The operating system to target this rpm for. You want to set this to 'linux' if you are using fpm on OS X, for example
|
||||
|
||||
* ``--rpm-posttrans FILE``
|
||||
- (rpm only) posttrans script
|
||||
|
||||
* ``--rpm-pretrans FILE``
|
||||
- (rpm only) pretrans script
|
||||
|
||||
* ``--rpm-rpmbuild-define DEFINITION``
|
||||
- (rpm only) Pass a --define argument to rpmbuild.
|
||||
|
||||
* ``--[no-]rpm-sign``
|
||||
- (rpm only) Pass --sign to rpmbuild
|
||||
|
||||
* ``--rpm-summary SUMMARY``
|
||||
- (rpm only) Set the RPM summary. Overrides the first line on the description if set
|
||||
|
||||
* ``--rpm-tag TAG``
|
||||
- (rpm only) Adds a custom tag in the spec file as is. Example: --rpm-tag 'Requires(post): /usr/sbin/alternatives'
|
||||
|
||||
* ``--rpm-trigger-after-install '[OPT]PACKAGE: FILEPATH'``
|
||||
- (rpm only) Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
|
||||
* ``--rpm-trigger-after-target-uninstall '[OPT]PACKAGE: FILEPATH'``
|
||||
- (rpm only) Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
|
||||
* ``--rpm-trigger-before-install '[OPT]PACKAGE: FILEPATH'``
|
||||
- (rpm only) Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
|
||||
* ``--rpm-trigger-before-uninstall '[OPT]PACKAGE: FILEPATH'``
|
||||
- (rpm only) Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
|
||||
* ``--[no-]rpm-use-file-permissions``
|
||||
- (rpm only) Use existing file permissions when defining ownership and modes.
|
||||
|
||||
* ``--rpm-user USER``
|
||||
- (rpm only) Set the user to USER in the %files section. Overrides the user when used with use-file-permissions setting.
|
||||
|
||||
* ``--[no-]rpm-verbatim-gem-dependencies``
|
||||
- (rpm only) When converting from a gem, leave the old (fpm 0.4.x) style dependency names. This flag will use the old 'rubygem-foo' names in rpm requires instead of the redhat style rubygem(foo).
|
||||
|
||||
* ``--rpm-verifyscript FILE``
|
||||
- (rpm only) a script to be run on verification
|
||||
|
||||
* ``--snap-confinement CONFINEMENT``
|
||||
- (snap only) Type of confinement to use for this snap.
|
||||
|
||||
* ``--snap-grade GRADE``
|
||||
- (snap only) Grade of this snap.
|
||||
|
||||
* ``--snap-yaml FILEPATH``
|
||||
- (snap only) Custom version of the snap.yaml file.
|
||||
|
||||
* ``--solaris-group GROUP``
|
||||
- (solaris only) Set the group to GROUP in the prototype file.
|
||||
|
||||
* ``--solaris-user USER``
|
||||
- (solaris only) Set the user to USER in the prototype files.
|
||||
|
||||
* ``--source-date-epoch-default SOURCE_DATE_EPOCH_DEFAULT``
|
||||
- If no release date otherwise specified, use this value as timestamp on generated files to reduce nondeterminism. Reproducible build environments such as dpkg-dev and rpmbuild set this via envionment variable SOURCE_DATE_EPOCH variable to the integer unix timestamp to use in generated archives, and expect tools like fpm to use it as a hint to avoid nondeterministic output. This is a Unix timestamp, i.e. number of seconds since 1 Jan 1970 UTC. See https://reproducible-builds.org/specs/source-date-epoch
|
||||
|
||||
|
|
@ -615,33 +165,6 @@ General Options
|
|||
* ``--verbose``
|
||||
- Enable verbose output
|
||||
|
||||
* ``--virtualenv-find-links PIP_FIND_LINKS``
|
||||
- (virtualenv only) If a url or path to an html file, then parse for links to archives. If a local path or file:// url that's a directory, then look for archives in the directory listing.
|
||||
|
||||
* ``--[no-]virtualenv-fix-name``
|
||||
- (virtualenv only) Should the target package name be prefixed?
|
||||
|
||||
* ``--virtualenv-install-location DIRECTORY``
|
||||
- (virtualenv only) DEPRECATED: Use --prefix instead. Location to which to install the virtualenv by default.
|
||||
|
||||
* ``--virtualenv-other-files-dir DIRECTORY``
|
||||
- (virtualenv only) Optionally, the contents of the specified directory may be added to the package. This is useful if the virtualenv needs configuration files, etc.
|
||||
|
||||
* ``--virtualenv-package-name-prefix PREFIX``
|
||||
- (virtualenv only) Name to prefix the package name with.
|
||||
|
||||
* ``--virtualenv-pypi PYPI_URL``
|
||||
- (virtualenv only) PyPi Server uri for retrieving packages.
|
||||
|
||||
* ``--virtualenv-pypi-extra-url PYPI_EXTRA_URL``
|
||||
- (virtualenv only) PyPi extra-index-url for pointing to your priviate PyPi
|
||||
|
||||
* ``--[no-]virtualenv-setup-install``
|
||||
- (virtualenv only) After building virtualenv run setup.py install useful when building a virtualenv for packages and including their requirements from
|
||||
|
||||
* ``--[no-]virtualenv-system-site-packages``
|
||||
- (virtualenv only) Give the virtual environment access to the global site-packages
|
||||
|
||||
* ``--workdir WORKDIR``
|
||||
- The directory you want fpm to do its work in, where 'work' is any file copying, downloading, etc. Roughly any scratch space fpm needs to build your package.
|
||||
|
||||
|
|
@ -690,7 +213,9 @@ deb
|
|||
* ``--deb-changelog FILEPATH``
|
||||
- Add FILEPATH as debian changelog
|
||||
* ``--deb-compression COMPRESSION``
|
||||
- The compression type to use, must be one of gz, bzip2, xz, none.
|
||||
- The compression type to use, must be one of gz, bzip2, xz, zst, none.
|
||||
* ``--deb-compression-level [0-9]``
|
||||
- Select a compression level. 0 is none or minimal. 9 is max compression.
|
||||
* ``--deb-config SCRIPTPATH``
|
||||
- Add SCRIPTPATH as debconf config file.
|
||||
* ``--deb-custom-control FILEPATH``
|
||||
|
|
@ -737,6 +262,8 @@ deb
|
|||
- Start service after install or upgrade
|
||||
* ``--[no-]deb-systemd-enable``
|
||||
- Enable service on install or upgrade
|
||||
* ``--deb-systemd-path FILEPATH``
|
||||
- Relative path to the systemd service directory
|
||||
* ``--[no-]deb-systemd-restart-after-upgrade``
|
||||
- Restart service after upgrade
|
||||
* ``--deb-templates FILEPATH``
|
||||
|
|
@ -765,6 +292,8 @@ freebsd
|
|||
|
||||
* ``--freebsd-origin ABI``
|
||||
- Sets the FreeBSD 'origin' pkg field
|
||||
* ``--freebsd-osversion VERSION``
|
||||
- Sets the FreeBSD 'version' pkg field, ie 12 or 13, use '*' for all.
|
||||
|
||||
gem
|
||||
---
|
||||
|
|
@ -898,7 +427,7 @@ python
|
|||
* ``--python-bin PYTHON_EXECUTABLE``
|
||||
- The path to the python executable you wish to run.
|
||||
* ``--[no-]python-dependencies``
|
||||
- Include requirements defined in setup.py as dependencies.
|
||||
- Include requirements defined by the python package as dependencies.
|
||||
* ``--python-disable-dependency python_package_name``
|
||||
- The python package name to remove from dependency list
|
||||
* ``--[no-]python-downcase-dependencies``
|
||||
|
|
@ -912,11 +441,11 @@ python
|
|||
* ``--[no-]python-fix-name``
|
||||
- Should the target package name be prefixed?
|
||||
* ``--python-install-bin BIN_PATH``
|
||||
- The path to where python scripts should be installed to.
|
||||
- (DEPRECATED, does nothing) The path to where python scripts should be installed to.
|
||||
* ``--python-install-data DATA_PATH``
|
||||
- The path to where data should be installed to. This is equivalent to 'python setup.py --install-data DATA_PATH
|
||||
- (DEPRECATED, does nothing) The path to where data should be installed to. This is equivalent to 'python setup.py --install-data DATA_PATH
|
||||
* ``--python-install-lib LIB_PATH``
|
||||
- The path to where python libs should be installed to (default depends on your python installation). Want to find out what your target platform is using? Run this: python -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()'
|
||||
- (DEPRECATED, does nothing) The path to where python libs should be installed to (default depends on your python installation). Want to find out what your target platform is using? Run this: python -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()'
|
||||
* ``--[no-]python-internal-pip``
|
||||
- Use the pip module within python to install modules - aka 'python -m pip'. This is the recommended usage since Python 3.4 (2014) instead of invoking the 'pip' script
|
||||
* ``--[no-]python-obey-requirements-txt``
|
||||
|
|
@ -930,9 +459,9 @@ python
|
|||
* ``--python-pypi PYPI_URL``
|
||||
- PyPi Server uri for retrieving packages.
|
||||
* ``--python-scripts-executable PYTHON_EXECUTABLE``
|
||||
- Set custom python interpreter in installing scripts. By default distutils will replace python interpreter in installing scripts (specified by shebang) with current python interpreter (sys.executable). This option is equivalent to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments to 'setup.py install' command.
|
||||
- (DEPRECATED) Set custom python interpreter in installing scripts. By default distutils will replace python interpreter in installing scripts (specified by shebang) with current python interpreter (sys.executable). This option is equivalent to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments to 'setup.py install' command.
|
||||
* ``--python-setup-py-arguments setup_py_argument``
|
||||
- Arbitrary argument(s) to be passed to setup.py
|
||||
- (DEPRECATED) Arbitrary argument(s) to be passed to setup.py
|
||||
* ``--python-trusted-host PYPI_TRUSTED``
|
||||
- Mark this host or host:port pair as trusted for pip
|
||||
|
||||
|
|
@ -976,7 +505,9 @@ rpm
|
|||
* ``--rpm-init FILEPATH``
|
||||
- Add FILEPATH as an init script
|
||||
* ``--[no-]rpm-macro-expansion``
|
||||
- install-time macro expansion in %pre %post %preun %postun scripts (see: https://rpm.org/user_doc/scriptlet_expansion.html)
|
||||
- install-time macro expansion in %pre %post %preun %postun scripts (see: https://rpm-software-management.github.io/rpm/manual/scriptlet_expansion.html)
|
||||
* ``--[no-]rpm-old-perl-dependency-name``
|
||||
- Use older 'perl' depdency name. Newer Red Hat (and derivatives) use a dependency named 'perl-interpreter'.
|
||||
* ``--rpm-os OS``
|
||||
- The operating system to target this rpm for. You want to set this to 'linux' if you are using fpm on OS X, for example
|
||||
* ``--rpm-posttrans FILE``
|
||||
|
|
@ -992,13 +523,13 @@ rpm
|
|||
* ``--rpm-tag TAG``
|
||||
- Adds a custom tag in the spec file as is. Example: --rpm-tag 'Requires(post): /usr/sbin/alternatives'
|
||||
* ``--rpm-trigger-after-install '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--rpm-trigger-after-target-uninstall '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--rpm-trigger-before-install '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--rpm-trigger-before-uninstall '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--[no-]rpm-use-file-permissions``
|
||||
- Use existing file permissions when defining ownership and modes.
|
||||
* ``--rpm-user USER``
|
||||
|
|
@ -1054,7 +585,7 @@ virtualenv
|
|||
* ``--virtualenv-pypi-extra-url PYPI_EXTRA_URL``
|
||||
- PyPi extra-index-url for pointing to your priviate PyPi
|
||||
* ``--[no-]virtualenv-setup-install``
|
||||
- After building virtualenv run setup.py install useful when building a virtualenv for packages and including their requirements from
|
||||
- After building virtualenv run setup.py install useful when building a virtualenv for packages and including their requirements from requirements.txt
|
||||
* ``--[no-]virtualenv-system-site-packages``
|
||||
- Give the virtual environment access to the global site-packages
|
||||
|
||||
|
|
|
|||
12
docs/conf.py
12
docs/conf.py
|
|
@ -28,7 +28,9 @@ import os
|
|||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
extensions = [
|
||||
'sphinx_rtd_theme'
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
|
@ -46,7 +48,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = u'fpm - packaging made simple'
|
||||
copyright = u'2016, Jordan Sissel'
|
||||
copyright = u'2025, Jordan Sissel and contributors'
|
||||
author = u'Jordan Sissel'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
|
@ -54,16 +56,16 @@ author = u'Jordan Sissel'
|
|||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'1.9'
|
||||
version = u'1.17'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'1.9.0'
|
||||
release = u'1.17.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
language = "en"
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
|
|
|
|||
|
|
@ -56,10 +56,15 @@ when it lists the FPM gem:
|
|||
If your system doesn't have `bsdtar` by default, make sure to install it or some
|
||||
tests will fail:
|
||||
|
||||
apt-get install bsdtar
|
||||
apt-get install bsdtar || apt install libarchive-tools
|
||||
|
||||
yum install bsdtar
|
||||
|
||||
|
||||
You also need these tools:
|
||||
|
||||
apt-get install lintian cpanminus
|
||||
|
||||
Next, run make in root of the FPM repo. If there are any problems (such as
|
||||
missing dependencies) you should receive an error
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ if ARGV.length == 0
|
|||
puts "General Options"
|
||||
puts "---------------"
|
||||
|
||||
FPM::Command.instance_variable_get(:@declared_options).sort_by { |o| flagsort.call(o.switches.first) }.each do |option|
|
||||
#FPM::Command.instance_variable_get(:@declared_options).sort_by { |o| flagsort.call(o.switches.first) }.each do |option|
|
||||
FPM::Command::GENERAL_OPTIONS.sort_by { |o| flagsort.call(o.switches.first) }.each do |option|
|
||||
text = option.description.gsub("\n", " ")
|
||||
|
||||
if option.type == :flag
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Installing FPM
|
|||
--------------
|
||||
|
||||
.. note::
|
||||
You must have ruby installed on your machine before installing fpm. `Here` are instructions to install Ruby on your machine.
|
||||
You must have ruby installed on your machine before installing fpm. `Here`_ are instructions to install Ruby on your machine.
|
||||
|
||||
.. _Here: https://www.ruby-lang.org/en/documentation/installation/
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ To make sure fpm is installed correctly, try running the following command::
|
|||
You should get some output like this, although the exact output will depend on which version of FPM you have installed.::
|
||||
|
||||
% fpm --version
|
||||
1.14.0
|
||||
1.17.0
|
||||
|
||||
Now you can go on to `using FPM! <getting-started.html>`_
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
* ``--deb-changelog FILEPATH``
|
||||
- Add FILEPATH as debian changelog
|
||||
* ``--deb-compression COMPRESSION``
|
||||
- The compression type to use, must be one of gz, bzip2, xz, none.
|
||||
- The compression type to use, must be one of gz, bzip2, xz, zst, none.
|
||||
* ``--deb-compression-level [0-9]``
|
||||
- Select a compression level. 0 is none or minimal. 9 is max compression.
|
||||
* ``--deb-config SCRIPTPATH``
|
||||
- Add SCRIPTPATH as debconf config file.
|
||||
* ``--deb-custom-control FILEPATH``
|
||||
|
|
@ -58,6 +60,8 @@
|
|||
- Start service after install or upgrade
|
||||
* ``--[no-]deb-systemd-enable``
|
||||
- Enable service on install or upgrade
|
||||
* ``--deb-systemd-path FILEPATH``
|
||||
- Relative path to the systemd service directory
|
||||
* ``--[no-]deb-systemd-restart-after-upgrade``
|
||||
- Restart service after upgrade
|
||||
* ``--deb-templates FILEPATH``
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
* ``--freebsd-origin ABI``
|
||||
- Sets the FreeBSD 'origin' pkg field
|
||||
* ``--freebsd-osversion VERSION``
|
||||
- Sets the FreeBSD 'version' pkg field, ie 12 or 13, use '*' for all.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
* ``--python-bin PYTHON_EXECUTABLE``
|
||||
- The path to the python executable you wish to run.
|
||||
* ``--[no-]python-dependencies``
|
||||
- Include requirements defined in setup.py as dependencies.
|
||||
- Include requirements defined by the python package as dependencies.
|
||||
* ``--python-disable-dependency python_package_name``
|
||||
- The python package name to remove from dependency list
|
||||
* ``--[no-]python-downcase-dependencies``
|
||||
|
|
@ -15,11 +15,11 @@
|
|||
* ``--[no-]python-fix-name``
|
||||
- Should the target package name be prefixed?
|
||||
* ``--python-install-bin BIN_PATH``
|
||||
- The path to where python scripts should be installed to.
|
||||
- (DEPRECATED, does nothing) The path to where python scripts should be installed to.
|
||||
* ``--python-install-data DATA_PATH``
|
||||
- The path to where data should be installed to. This is equivalent to 'python setup.py --install-data DATA_PATH
|
||||
- (DEPRECATED, does nothing) The path to where data should be installed to. This is equivalent to 'python setup.py --install-data DATA_PATH
|
||||
* ``--python-install-lib LIB_PATH``
|
||||
- The path to where python libs should be installed to (default depends on your python installation). Want to find out what your target platform is using? Run this: python -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()'
|
||||
- (DEPRECATED, does nothing) The path to where python libs should be installed to (default depends on your python installation). Want to find out what your target platform is using? Run this: python -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()'
|
||||
* ``--[no-]python-internal-pip``
|
||||
- Use the pip module within python to install modules - aka 'python -m pip'. This is the recommended usage since Python 3.4 (2014) instead of invoking the 'pip' script
|
||||
* ``--[no-]python-obey-requirements-txt``
|
||||
|
|
@ -33,9 +33,9 @@
|
|||
* ``--python-pypi PYPI_URL``
|
||||
- PyPi Server uri for retrieving packages.
|
||||
* ``--python-scripts-executable PYTHON_EXECUTABLE``
|
||||
- Set custom python interpreter in installing scripts. By default distutils will replace python interpreter in installing scripts (specified by shebang) with current python interpreter (sys.executable). This option is equivalent to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments to 'setup.py install' command.
|
||||
- (DEPRECATED) Set custom python interpreter in installing scripts. By default distutils will replace python interpreter in installing scripts (specified by shebang) with current python interpreter (sys.executable). This option is equivalent to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments to 'setup.py install' command.
|
||||
* ``--python-setup-py-arguments setup_py_argument``
|
||||
- Arbitrary argument(s) to be passed to setup.py
|
||||
- (DEPRECATED) Arbitrary argument(s) to be passed to setup.py
|
||||
* ``--python-trusted-host PYPI_TRUSTED``
|
||||
- Mark this host or host:port pair as trusted for pip
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@
|
|||
* ``--rpm-init FILEPATH``
|
||||
- Add FILEPATH as an init script
|
||||
* ``--[no-]rpm-macro-expansion``
|
||||
- install-time macro expansion in %pre %post %preun %postun scripts (see: https://rpm.org/user_doc/scriptlet_expansion.html)
|
||||
- install-time macro expansion in %pre %post %preun %postun scripts (see: https://rpm-software-management.github.io/rpm/manual/scriptlet_expansion.html)
|
||||
* ``--[no-]rpm-old-perl-dependency-name``
|
||||
- Use older 'perl' depdency name. Newer Red Hat (and derivatives) use a dependency named 'perl-interpreter'.
|
||||
* ``--rpm-os OS``
|
||||
- The operating system to target this rpm for. You want to set this to 'linux' if you are using fpm on OS X, for example
|
||||
* ``--rpm-posttrans FILE``
|
||||
|
|
@ -51,13 +53,13 @@
|
|||
* ``--rpm-tag TAG``
|
||||
- Adds a custom tag in the spec file as is. Example: --rpm-tag 'Requires(post): /usr/sbin/alternatives'
|
||||
* ``--rpm-trigger-after-install '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--rpm-trigger-after-target-uninstall '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--rpm-trigger-before-install '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--rpm-trigger-before-uninstall '[OPT]PACKAGE: FILEPATH'``
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: http://rpm.org/api/4.4.2.2/triggers.html
|
||||
- Adds a rpm trigger script located in FILEPATH, having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. See: https://rpm-software-management.github.io/rpm/manual/triggers.html
|
||||
* ``--[no-]rpm-use-file-permissions``
|
||||
- Use existing file permissions when defining ownership and modes.
|
||||
* ``--rpm-user USER``
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* ``--virtualenv-pypi-extra-url PYPI_EXTRA_URL``
|
||||
- PyPi extra-index-url for pointing to your priviate PyPi
|
||||
* ``--[no-]virtualenv-setup-install``
|
||||
- After building virtualenv run setup.py install useful when building a virtualenv for packages and including their requirements from
|
||||
- After building virtualenv run setup.py install useful when building a virtualenv for packages and including their requirements from requirements.txt
|
||||
* ``--[no-]virtualenv-system-site-packages``
|
||||
- Give the virtual environment access to the global site-packages
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,6 @@ Fun Examples
|
|||
Do you have any examples you want to share that use the ``cpan`` package type? Share your knowledge here: https://github.com/jordansissel/fpm/issues/new
|
||||
|
||||
cpan-specific command line flags
|
||||
-------------------------------
|
||||
--------------------------------
|
||||
|
||||
.. include:: cli/cpan.rst
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Any number of arguments are supported and behave as follows:
|
|||
1) A path to a local file or directory will be put into the output package as-is with the same path, contents, and metadata (file owner, modification date, etc)
|
||||
2) A syntax of "localpath=destinationpath" to copy local paths into the output package with the destination path.
|
||||
|
||||
The local file paths are modified by the ``--chdir`` flag. The destination file paths are modified by the `--prefix`` flag.
|
||||
The local file paths are modified by the ``--chdir`` flag. The destination file paths are modified by the ``--prefix`` flag.
|
||||
|
||||
Sample Usage
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ Supported Uses in FPM
|
|||
fpm supports using ``freebsd`` only as an output type. This means you can create ``freebsd`` packages from input types like ``deb``, ``dir``, or ``npm``
|
||||
|
||||
freebsd-specific command line flags
|
||||
-------------------------------
|
||||
-----------------------------------
|
||||
|
||||
.. include:: cli/freebsd.rst
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ output type (such as a `dir` or `rpm`). It also means you can create a ``.pkg``
|
|||
package file.
|
||||
|
||||
osxpkg-specific command line flags
|
||||
-------------------------------
|
||||
----------------------------------
|
||||
|
||||
.. include:: cli/osxpkg.rst
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ Supported Uses in FPM
|
|||
fpm supports input and output for Arch Linux's package format, pacman. This means you can read a pacman and convert it to a different output type (such as a `dir` or `rpm`). It also means you can create a pacman package.
|
||||
|
||||
pacman-specific command line flags
|
||||
-------------------------------
|
||||
----------------------------------
|
||||
|
||||
.. include:: cli/pacman.rst
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ Supported Uses in FPM
|
|||
fpm supports using ``pkgin`` only as an output type. This means you can create ``pkgin`` packages from input types like ``deb``, ``dir``, or ``npm``
|
||||
|
||||
pkgin-specific command line flags
|
||||
-------------------------------
|
||||
---------------------------------
|
||||
|
||||
.. include:: cli/pkgin.rst
|
||||
|
|
|
|||
|
|
@ -18,6 +18,6 @@ fpm supports using ``pleaserun`` only as an input type. This means you can conve
|
|||
``pleaserun`` input packages to output packages like ``deb``, ``rpm``, and more.
|
||||
|
||||
pleaserun-specific command line flags
|
||||
-------------------------------
|
||||
-------------------------------------
|
||||
|
||||
.. include:: cli/pleaserun.rst
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ This package format is typically used in older Solaris versions (Solaris 7, 8,
|
|||
|
||||
If you're using Solaris 11, OpenSolaris, or Illumos, you might want to use `the newer package format, p5p`_.
|
||||
|
||||
.. _newer package format, p5p: /packages/p5p.html
|
||||
.. _the newer package format, p5p: /packages/p5p.html
|
||||
|
||||
Supported Uses in FPM
|
||||
---------------------
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
# https://blog.readthedocs.com/build-errors-docutils-0-18/
|
||||
docutils<0.18
|
||||
sphinx_rtd_theme
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
$: << File.join(File.dirname(__FILE__), "..", "..", "lib")
|
||||
|
||||
# This example uses the API to create a package from local files
|
||||
# it also creates necessary init-scripts and systemd files so our executable can be used as a service
|
||||
|
||||
require "fpm"
|
||||
require "tmpdir"
|
||||
require "fpm/package/pleaserun"
|
||||
|
||||
# enable logging
|
||||
FPM::Util.send :module_function, :logger
|
||||
FPM::Util.logger.level = :info
|
||||
FPM::Util.logger.subscribe STDERR
|
||||
|
||||
package = FPM::Package::Dir.new
|
||||
|
||||
# Set some attributes
|
||||
package.name = "my-service"
|
||||
package.version = "1.0"
|
||||
|
||||
# Add a script to run after install (should be in the current directory):
|
||||
package.scripts[:after_install] = 'my_after_install_script.sh'
|
||||
|
||||
# Example for adding special attributes
|
||||
package.attributes[:deb_group] = "super-useful"
|
||||
package.attributes[:rpm_group] = "super-useful"
|
||||
|
||||
# Add our files (should be in the current directory):
|
||||
package.input("my-executable=/usr/bin/")
|
||||
package.input("my-library.so=/usr/lib/")
|
||||
|
||||
# Now, add our init-scripts, systemd services, and so on:
|
||||
pleaserun = package.convert(FPM::Package::PleaseRun)
|
||||
pleaserun.input ["/usr/bin/my-executable", "--foo-from", "bar"]
|
||||
|
||||
# Create two output packages!
|
||||
output_packages = []
|
||||
output_packages << pleaserun.convert(FPM::Package::RPM)
|
||||
output_packages << pleaserun.convert(FPM::Package::Deb)
|
||||
|
||||
# and write them both.
|
||||
begin
|
||||
output_packages.each do |output_package|
|
||||
output = output_package.to_s
|
||||
output_package.output(output)
|
||||
|
||||
puts "successfully created #{output}"
|
||||
end
|
||||
ensure
|
||||
# defer cleanup until the end
|
||||
output_packages.each {|p| p.cleanup}
|
||||
end
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
$: << File.join(File.dirname(__FILE__), "..", "..", "lib")
|
||||
require "fpm"
|
||||
|
||||
package = FPM::Package::Gem.new
|
||||
|
||||
# the Gem package takes a string name of the package to download/install.
|
||||
# Example, run this script with 'rails' as an argument and it will convert
|
||||
# the latest 'rails' gem into rpm.
|
||||
package.input(ARGV[0])
|
||||
rpm = package.convert(FPM::Package::RPM)
|
||||
begin
|
||||
output = "NAME-VERSION.ARCH.rpm"
|
||||
rpm.output(rpm.to_s(output))
|
||||
ensure
|
||||
rpm.cleanup
|
||||
end
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
$: << File.join(File.dirname(__FILE__), "..", "..", "lib")
|
||||
require "fpm"
|
||||
|
||||
package = FPM::Package::Gem.new
|
||||
ARGV.each do |gem|
|
||||
name, version = gem.split(/[=]/, 2)
|
||||
package.version = version # Allow specifying a specific version
|
||||
package.input(gem)
|
||||
end
|
||||
rpm = package.convert(FPM::Package::RPM)
|
||||
rpm.name = "rubygem-manythings"
|
||||
rpm.version = "1.0"
|
||||
begin
|
||||
output = "NAME-VERSION.ARCH.rpm"
|
||||
rpm.output(rpm.to_s(output))
|
||||
ensure
|
||||
rpm.cleanup
|
||||
end
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
#
|
||||
# feel free to change these to whatever makes sense
|
||||
#
|
||||
# debian package we rely on
|
||||
RUBY_PACKAGE=ruby
|
||||
# and the executable that comes from it
|
||||
RUBY_BIN=/usr/bin/ruby
|
||||
# the version we name the deb
|
||||
VERSION=1.1.0
|
||||
# where to get the sauce
|
||||
GIT_URL=https://github.com/jordansissel/fpm.git
|
||||
# the tag we checkout to build from
|
||||
TAG_SPEC=refs/tags/v$(VERSION)
|
||||
|
||||
CHECKOUT_DIR=fpm-checkout
|
||||
BUILD_DIR=build
|
||||
LIB_DIR=$(BUILD_DIR)/usr/lib/fpm
|
||||
BIN_DIR=$(BUILD_DIR)/usr/bin
|
||||
GEM_PATH:=$(shell readlink -f .)/build/gem
|
||||
FPM_BIN=$(BIN_DIR)/fpm
|
||||
BUNDLE_BIN=$(GEM_PATH)/bin/bundle
|
||||
BUNDLE_CMD=$(RUBY_CMD) $(BUNDLE_BIN)
|
||||
FPM_CMD=$(FPM_BIN)
|
||||
GEM_CMD=$(RUBY_BIN) -S gem
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(CHECKOUT_DIR)
|
||||
rm -rf $(BUILD_DIR)
|
||||
rm -f fpm*.deb
|
||||
|
||||
$(CHECKOUT_DIR):
|
||||
rm -rf $(CHECKOUT_DIR)
|
||||
git clone $(GIT_URL) $(CHECKOUT_DIR) --depth 1
|
||||
cd $(CHECKOUT_DIR) && git fetch && git checkout $(TAG_SPEC)
|
||||
|
||||
$(BUNDLE_BIN):
|
||||
$(GEM_CMD) install bundler --install-dir=$(GEM_PATH) --no-ri --no-rdoc
|
||||
|
||||
$(FPM_BIN):
|
||||
mkdir --parents $(BIN_DIR)
|
||||
# Couldn't think of a nice way to do this, so here is this code turd
|
||||
echo "#! $(RUBY_BIN)" > $(FPM_BIN)
|
||||
echo 'load File.dirname($$0) + "/../lib/fpm/bundle/bundler/setup.rb"' >> $(FPM_BIN)
|
||||
echo 'require "fpm"' >> $(FPM_BIN)
|
||||
echo 'require "fpm/command"' >> $(FPM_BIN)
|
||||
echo 'exit(FPM::Command.run || 0)' >> $(FPM_BIN)
|
||||
chmod +x $(FPM_BIN)
|
||||
|
||||
.PHONY: install
|
||||
install: $(CHECKOUT_DIR) $(BUNDLE_BIN) $(FPM_BIN)
|
||||
mkdir --parents $(LIB_DIR)
|
||||
cd $(CHECKOUT_DIR) && GEM_PATH=$(GEM_PATH) $(BUNDLE_CMD) install --without=development --standalone
|
||||
cd $(CHECKOUT_DIR) && gem build fpm.gemspec
|
||||
tar -xf $(CHECKOUT_DIR)/fpm*gem -C $(BUILD_DIR)
|
||||
tar --touch -xf $(BUILD_DIR)/data.tar.gz -C $(LIB_DIR)
|
||||
cp -r $(CHECKOUT_DIR)/bundle $(LIB_DIR)/bundle
|
||||
|
||||
.PHONY: package
|
||||
package: install
|
||||
$(FPM_BIN) -s dir -t deb -n fpm -d $(RUBY_PACKAGE) -v $(VERSION) -C $(BUILD_DIR) usr
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# About
|
||||
|
||||
- build and install dependency on a ruby1.9 of some kind
|
||||
- does not need root to package
|
||||
- has its own GEM_DIR to keep its dependencies isolated
|
||||
- installation does not install any gems in to your ruby environment
|
||||
- installs in to standard locations /usr/{bin,lib}/fpm
|
||||
- doesn't depend on having fpm installed for packaging to work
|
||||
|
||||
# Dependencies
|
||||
|
||||
- build-essential (perhaps more, but basically the standard packages you need
|
||||
for deb packaging)
|
||||
- ruby and ruby-dev
|
||||
|
||||
# Usage
|
||||
|
||||
- $ cd examples/fpm-with-system-ruby && make package
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
NAME=ruby
|
||||
VERSION=1.9.2-p180
|
||||
MAJOR_VERSION=1.9
|
||||
ARCHITECTURE=x86
|
||||
TARDIR=$(NAME)-$(VERSION)
|
||||
TARBALL=$(TARDIR).tar.gz
|
||||
DOWNLOAD=http://ftp.ruby-lang.org/pub/ruby/$(MAJOR_VERSION)/$(TARBALL)
|
||||
|
||||
PREFIX=/opt/fpm
|
||||
|
||||
PACKAGE_NAME=fpm
|
||||
PACKAGE_VERSION=0.2.30
|
||||
|
||||
.PHONY: default
|
||||
default: deb
|
||||
package: deb
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(NAME)-* $(NAME)_* |NAME| true
|
||||
rm -fr $(TARDIR) || true
|
||||
rm -fr $(PREFIX) || true
|
||||
rm -f *.deb
|
||||
|
||||
$(TARBALL):
|
||||
wget "$(DOWNLOAD)"
|
||||
|
||||
$(TARDIR): $(TARBALL)
|
||||
tar -zxf $(TARBALL)
|
||||
cd $(TARDIR); ./configure --enable-shared=false --prefix=$(PREFIX); make; make install
|
||||
$(PREFIX)/bin/gem install fpm
|
||||
|
||||
.PHONY: deb
|
||||
deb: $(TARDIR)
|
||||
$(PREFIX)/bin/fpm -s dir -t deb -v $(PACKAGE_VERSION) -n $(PACKAGE_NAME) -a $(ARCHITECTURE) -C $(PREFIX) .
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Notes:
|
||||
|
||||
You should have write permission on /opt directory
|
||||
|
||||
Dependencies:
|
||||
|
||||
$ sudo apt-get install build-essential bison openssl libreadline6 libreadline6-dev zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libxml2-dev libxslt-dev autoconf libc6-dev
|
||||
|
||||
Usage:
|
||||
|
||||
$ make package
|
||||
|
||||
Should make the package. Try installing:
|
||||
|
||||
$ sudo dpkg -i fpm-0.2.30.x86.deb
|
||||
|
||||
Now try it:
|
||||
|
||||
$ /opt/fpm/bin/fpm --help
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
NAME=jruby
|
||||
VERSION=1.6.1
|
||||
DOWNLOAD=http://jruby.org.s3.amazonaws.com/downloads/$(VERSION)/$(TARBALL)
|
||||
TARBALL=$(NAME)-bin-$(VERSION).tar.gz
|
||||
TARDIR=$(NAME)-$(VERSION)
|
||||
|
||||
PREFIX=/opt/jruby
|
||||
|
||||
.PHONY: default
|
||||
default: deb
|
||||
package: deb
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(NAME)-* $(NAME)_* || true
|
||||
rm -fr $(TARDIR) || true
|
||||
rm -f *.deb
|
||||
rm -f *.rpm
|
||||
|
||||
$(TARBALL):
|
||||
wget "$(DOWNLOAD)"
|
||||
|
||||
$(TARDIR): $(TARBALL)
|
||||
tar -zxf $(TARBALL)
|
||||
|
||||
.PHONY: deb
|
||||
deb: $(TARDIR)
|
||||
fpm -s dir -t deb -v $(VERSION) -n $(NAME) -d "sun-java6-bin (>> 0)" \
|
||||
-a all -d "sun-java6-jre (>> 0)" --prefix $(PREFIX) -C $(TARDIR) .
|
||||
|
||||
.PHONY: rpm
|
||||
rpm: $(TARDIR)
|
||||
fpm -s dir -t rpm -v $(VERSION) -n $(NAME) -d "jdk >= 1.6.0" \
|
||||
-a all --prefix $(PREFIX) -C $(TARDIR) .
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
Usage:
|
||||
|
||||
make package
|
||||
|
||||
Should make the package. Try installing:
|
||||
|
||||
sudo dpkg -i jruby-1.6.0.RC2-1.all.deb
|
||||
|
||||
Now try it:
|
||||
|
||||
% /opt/jruby/bin/jirb
|
||||
>> require "java"
|
||||
=> true
|
||||
>> java.lang.System.out.println("Hello")
|
||||
Hello
|
||||
=> nil
|
||||
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
NAME=twisted
|
||||
VERSION=10.2.0
|
||||
|
||||
twisted:
|
||||
easy_install --editable --build-directory . "$(NAME)==$(VERSION)"
|
||||
|
||||
usr: twisted
|
||||
cd twisted; python setup.py bdist
|
||||
tar -zxf twisted/dist/Twisted-$(VERSION).linux-$(shell uname -m).tar.gz
|
||||
|
||||
package: usr
|
||||
fpm -s dir -t deb -n $(NAME) -v $(VERSION) \
|
||||
-p python-$(NAME)-VERSION_ARCH.deb -d "python" \
|
||||
usr
|
||||
|
||||
|
|
@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|||
|
||||
# For logging
|
||||
# https://github.com/jordansissel/ruby-cabin
|
||||
spec.add_dependency("cabin", ">= 0.6.0") # license: Apache 2
|
||||
spec.add_dependency("cabin", ">= 0.9.1") # license: Apache 2
|
||||
|
||||
# For backports to older rubies
|
||||
# https://github.com/marcandre/backports
|
||||
|
|
@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|||
|
||||
# For command-line flag support
|
||||
# https://github.com/mdub/clamp/blob/master/README.markdown
|
||||
spec.add_dependency("clamp", "~> 1.0.0") # license: MIT
|
||||
spec.add_dependency("clamp", ">= 1.0.0") # license: MIT
|
||||
|
||||
# For sourcing from pleaserun
|
||||
spec.add_dependency("pleaserun", "~> 0.0.29") # license: Apache 2
|
||||
|
|
@ -46,7 +46,7 @@ Gem::Specification.new do |spec|
|
|||
# so I think this needs to be added explicitly?
|
||||
spec.add_dependency("rexml")
|
||||
|
||||
spec.add_development_dependency("rspec", "~> 3.0.0") # license: MIT (according to wikipedia)
|
||||
spec.add_development_dependency("rspec", "~> 3.13.0") # license: MIT (according to wikipedia)
|
||||
spec.add_development_dependency("insist", "~> 1.0.0") # license: Apache 2
|
||||
spec.add_development_dependency("pry")
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ require "fpm/namespace"
|
|||
require "fpm/version"
|
||||
require "fpm/util"
|
||||
require "clamp"
|
||||
require "ostruct"
|
||||
require "fpm"
|
||||
require "tmpdir" # for Dir.tmpdir
|
||||
|
||||
|
|
@ -260,7 +259,11 @@ class FPM::Command < Clamp::Command
|
|||
"'gem', it specifies the packages to download and use as the gem input",
|
||||
:attribute_name => :args
|
||||
|
||||
# Keep a copy of the original flags (ones declared above, not by package types)
|
||||
# This helps when generating the documentation
|
||||
GENERAL_OPTIONS = @declared_options.clone
|
||||
FPM::Package.types.each do |name, klass|
|
||||
# This adds each package's flags to the main command
|
||||
klass.apply_options(self)
|
||||
end
|
||||
|
||||
|
|
@ -410,7 +413,12 @@ class FPM::Command < Clamp::Command
|
|||
set = proc do |object, attribute|
|
||||
# if the package's attribute is currently nil *or* the flag setting for this
|
||||
# attribute is non-default, use the value.
|
||||
if object.send(attribute).nil? || send(attribute) != send("default_#{attribute}")
|
||||
|
||||
# Not all options have a default value, so we assume `nil` if there's no default. (#1543)
|
||||
# In clamp >= 1.3.0, options without `:default => ..` will not have any # `default_xyz`
|
||||
# methods generated, so we need to check for the presence of this method first.
|
||||
default = respond_to?("default_#{attribute}") ? send("default_#{attribute}") : nil
|
||||
if object.send(attribute).nil? || send(attribute) != default
|
||||
logger.info("Setting from flags: #{attribute}=#{send(attribute)}")
|
||||
object.send("#{attribute}=", send(attribute))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ require "fpm/util" # local
|
|||
require "pathname" # stdlib
|
||||
require "find"
|
||||
require "tmpdir" # stdlib
|
||||
require "ostruct"
|
||||
require "backports/latest"
|
||||
require "socket" # stdlib, for Socket.gethostname
|
||||
require "shellwords" # stdlib, for Shellwords.escape
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class FPM::Package::Deb < FPM::Package
|
|||
} unless defined?(SCRIPT_MAP)
|
||||
|
||||
# The list of supported compression types. Default is gz (gzip)
|
||||
COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "none" ]
|
||||
COMPRESSION_TYPES = [ "gz", "bzip2", "xz", "zst", "none" ]
|
||||
|
||||
# https://www.debian.org/doc/debian-policy/ch-relationships.html#syntax-of-relationship-fields
|
||||
# Example value with version relationship: libc6 (>= 2.2.1)
|
||||
|
|
@ -73,12 +73,25 @@ class FPM::Package::Deb < FPM::Package
|
|||
option "--compression", "COMPRESSION", "The compression type to use, must " \
|
||||
"be one of #{COMPRESSION_TYPES.join(", ")}.", :default => "gz" do |value|
|
||||
if !COMPRESSION_TYPES.include?(value)
|
||||
raise ArgumentError, "deb compression value of '#{value}' is invalid. " \
|
||||
raise FPM::Package::InvalidArgument, "deb compression value of '#{value}' is invalid. " \
|
||||
"Must be one of #{COMPRESSION_TYPES.join(", ")}"
|
||||
end
|
||||
value
|
||||
end
|
||||
|
||||
option "--compression-level", "[0-9]", "Select a compression level. 0 is none or minimal. 9 is max compression.",
|
||||
# Specify which compression level to use on the compressor backend, when building a package
|
||||
:default => nil do |value|
|
||||
valint = value.to_i
|
||||
# if self.attributes[:deb_compression].nil?
|
||||
# raise "Can't specify a compression level with compression disabled"
|
||||
# end
|
||||
unless value =~ /^\d$/ && valint >= 0 && valint <= 9
|
||||
raise "Invalid compression level '#{value}'. Valid values are integers between 0 and 9 inclusive."
|
||||
end
|
||||
valint
|
||||
end
|
||||
|
||||
option "--dist", "DIST-TAG", "Set the deb distribution.", :default => "unstable"
|
||||
|
||||
# Take care about the case when we want custom control file but still use fpm ...
|
||||
|
|
@ -210,6 +223,11 @@ class FPM::Package::Deb < FPM::Package
|
|||
next File.expand_path(file)
|
||||
end
|
||||
|
||||
option "--systemd-path", "FILEPATH", "Relative path to the systemd service directory",
|
||||
:default => "lib/systemd/system" do |file|
|
||||
next file.gsub(/^\/*/, '')
|
||||
end
|
||||
|
||||
option "--systemd-enable", :flag , "Enable service on install or upgrade", :default => false
|
||||
|
||||
option "--systemd-auto-start", :flag , "Start service after install or upgrade", :default => false
|
||||
|
|
@ -262,6 +280,9 @@ class FPM::Package::Deb < FPM::Package
|
|||
when "noarch"
|
||||
# Debian calls noarch "all"
|
||||
@architecture = "all"
|
||||
when "ppc64le"
|
||||
# Debian calls ppc64le "ppc64el"
|
||||
@architecture = "ppc64el"
|
||||
end
|
||||
return @architecture
|
||||
end # def architecture
|
||||
|
|
@ -332,6 +353,9 @@ class FPM::Package::Deb < FPM::Package
|
|||
when "xz"
|
||||
controltar = "control.tar.xz"
|
||||
compression = "-J"
|
||||
when "zst"
|
||||
controltar = "control.tar.zst"
|
||||
compression = "--use-compress-program 'zstd -d'"
|
||||
when 'tar'
|
||||
controltar = "control.tar"
|
||||
compression = ""
|
||||
|
|
@ -344,7 +368,7 @@ class FPM::Package::Deb < FPM::Package
|
|||
|
||||
build_path("control").tap do |path|
|
||||
FileUtils.mkdir(path) if !File.directory?(path)
|
||||
# unpack the control.tar.{,gz,bz2,xz} from the deb package into staging_path
|
||||
# unpack the control.tar.{,gz,bz2,xz,zst} from the deb package into staging_path
|
||||
# Unpack the control tarball
|
||||
safesystem(ar_cmd[0] + " p #{package} #{controltar} | tar #{compression} -xf - -C #{path}")
|
||||
|
||||
|
|
@ -364,7 +388,7 @@ class FPM::Package::Deb < FPM::Package
|
|||
version_re = /^(?:([0-9]+):)?(.+?)(?:-(.*))?$/
|
||||
m = version_re.match(parse.call("Version"))
|
||||
if !m
|
||||
raise "Unsupported version string '#{parse.call("Version")}'"
|
||||
raise FPM::InvalidPackageConfiguration, "Unsupported version string '#{parse.call("Version")}'"
|
||||
end
|
||||
self.epoch, self.version, self.iteration = m.captures
|
||||
|
||||
|
|
@ -454,6 +478,9 @@ class FPM::Package::Deb < FPM::Package
|
|||
when "xz"
|
||||
datatar = "data.tar.xz"
|
||||
compression = "-J"
|
||||
when "zst"
|
||||
datatar = "data.tar.zst"
|
||||
compression = "--use-compress-program 'zstd -d'"
|
||||
when 'tar'
|
||||
datatar = "data.tar"
|
||||
compression = ""
|
||||
|
|
@ -504,27 +531,36 @@ class FPM::Package::Deb < FPM::Package
|
|||
end
|
||||
if attributes[:source_date_epoch] == "0"
|
||||
logger.error("Alas, ruby's Zlib::GzipWriter does not support setting an mtime of zero. Aborting.")
|
||||
raise "#{name}: source_date_epoch of 0 not supported."
|
||||
raise FPM::InvalidPackageConfiguration, "#{name}: source_date_epoch of 0 not supported."
|
||||
end
|
||||
if not attributes[:source_date_epoch].nil? and not ar_cmd_deterministic?
|
||||
logger.error("Alas, could not find an ar that can handle -D option. Try installing recent gnu binutils. Aborting.")
|
||||
raise "#{name}: ar is insufficient to support source_date_epoch."
|
||||
raise FPM::InvalidPackageConfiguration, "#{name}: ar is insufficient to support source_date_epoch."
|
||||
end
|
||||
if not attributes[:source_date_epoch].nil? and not tar_cmd_supports_sort_names_and_set_mtime?
|
||||
logger.error("Alas, could not find a tar that can set mtime and sort. Try installing recent gnu tar. Aborting.")
|
||||
raise "#{name}: tar is insufficient to support source_date_epoch."
|
||||
raise FPM::InvalidPackageConfiguration, "#{name}: tar is insufficient to support source_date_epoch."
|
||||
end
|
||||
|
||||
attributes[:deb_systemd] = []
|
||||
attributes.fetch(:deb_systemd_list, []).each do |systemd|
|
||||
name = File.basename(systemd, ".service")
|
||||
dest_systemd = staging_path("lib/systemd/system/#{name}.service")
|
||||
name = File.basename(systemd)
|
||||
extname = File.extname(name)
|
||||
|
||||
name_with_extension = if extname.empty?
|
||||
"#{name}.service"
|
||||
elsif [".service", ".timer"].include?(extname)
|
||||
name
|
||||
else
|
||||
raise FPM::InvalidPackageConfiguration, "Invalid systemd unit file extension: #{extname}. Expected .service or .timer, or no extension."
|
||||
end
|
||||
|
||||
dest_systemd = staging_path(File.join(attributes[:deb_systemd_path], "#{name_with_extension}"))
|
||||
mkdir_p(File.dirname(dest_systemd))
|
||||
FileUtils.cp(systemd, dest_systemd)
|
||||
File.chmod(0644, dest_systemd)
|
||||
|
||||
# add systemd service name to attribute
|
||||
attributes[:deb_systemd] << name
|
||||
attributes[:deb_systemd] << name_with_extension
|
||||
end
|
||||
|
||||
if script?(:before_upgrade) or script?(:after_upgrade) or attributes[:deb_systemd].any?
|
||||
|
|
@ -627,8 +663,12 @@ class FPM::Package::Deb < FPM::Package
|
|||
end
|
||||
|
||||
attributes.fetch(:deb_systemd_list, []).each do |systemd|
|
||||
name = File.basename(systemd, ".service")
|
||||
dest_systemd = staging_path("lib/systemd/system/#{name}.service")
|
||||
name = File.basename(systemd)
|
||||
extname = File.extname(systemd)
|
||||
name_with_extension = extname.empty? ? "#{name}.service" : name
|
||||
|
||||
dest_systemd = staging_path(File.join(attributes[:deb_systemd_path], "#{name_with_extension}"))
|
||||
|
||||
mkdir_p(File.dirname(dest_systemd))
|
||||
FileUtils.cp(systemd, dest_systemd)
|
||||
File.chmod(0644, dest_systemd)
|
||||
|
|
@ -642,18 +682,29 @@ class FPM::Package::Deb < FPM::Package
|
|||
datatar = build_path("data.tar.gz")
|
||||
controltar = build_path("control.tar.gz")
|
||||
compression_flags = ["-z"]
|
||||
# gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
|
||||
compressor_options = {"GZIP" => "-#{self.attributes[:deb_compression_level] || 9}" +
|
||||
"#{'n' if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?}"}
|
||||
when "bzip2"
|
||||
datatar = build_path("data.tar.bz2")
|
||||
controltar = build_path("control.tar.gz")
|
||||
compression_flags = ["-j"]
|
||||
compressor_options = {"BZIP" => "-#{self.attributes[:deb_compression_level] || 9}"}
|
||||
when "xz"
|
||||
datatar = build_path("data.tar.xz")
|
||||
controltar = build_path("control.tar.xz")
|
||||
compression_flags = ["-J"]
|
||||
compressor_options = {"XZ_OPT" => "-#{self.attributes[:deb_compression_level] || 3}"}
|
||||
when "zst"
|
||||
datatar = build_path("data.tar.zst")
|
||||
controltar = build_path("control.tar.zst")
|
||||
compression_flags = ["--use-compress-program", "zstd"]
|
||||
compressor_options = {"ZSTD_CLEVEL" => "-#{self.attributes[:deb_compression_level] || 3}"}
|
||||
when "none"
|
||||
datatar = build_path("data.tar")
|
||||
controltar = build_path("control.tar")
|
||||
compression_flags = []
|
||||
compressor_options = {}
|
||||
else
|
||||
raise FPM::InvalidPackageConfiguration,
|
||||
"Unknown compression type '#{self.attributes[:deb_compression]}'"
|
||||
|
|
@ -662,9 +713,8 @@ class FPM::Package::Deb < FPM::Package
|
|||
if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
|
||||
# Use gnu tar options to force deterministic file order and timestamp
|
||||
args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
|
||||
# gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
|
||||
args.unshift({"GZIP" => "-9n"})
|
||||
end
|
||||
args.unshift(compressor_options)
|
||||
safesystem(*args)
|
||||
|
||||
# pack up the .deb, which is just an 'ar' archive with 3 files
|
||||
|
|
@ -704,9 +754,17 @@ class FPM::Package::Deb < FPM::Package
|
|||
self.dependencies = self.dependencies.collect do |dep|
|
||||
fix_dependency(dep)
|
||||
end.flatten
|
||||
|
||||
# If an invalid depends field was found i.e. /bin.sh then fix_depends will blank it
|
||||
# Make sure we remove this blank here
|
||||
self.dependencies = self.dependencies.reject { |p| p.empty? }
|
||||
|
||||
self.provides = self.provides.collect do |provides|
|
||||
fix_provides(provides)
|
||||
end.flatten
|
||||
# If an invalid provides field was found i.e. mypackage(arch) then fix_provides will blank it
|
||||
# Make sure we remove this blank here
|
||||
self.provides = self.provides.reject { |p| p.empty? }
|
||||
|
||||
if origin == FPM::Package::CPAN
|
||||
# The fpm cpan code presents dependencies and provides fields as perl(ModuleName)
|
||||
|
|
@ -721,7 +779,7 @@ class FPM::Package::Deb < FPM::Package
|
|||
else
|
||||
# Also replace '::' in the perl module name with '-'
|
||||
modulename = m["name"].gsub("::", "-")
|
||||
|
||||
|
||||
# Fix any upper-casing or other naming concerns Debian has about packages
|
||||
name = "#{attributes[:cpan_package_name_prefix]}-#{modulename}"
|
||||
|
||||
|
|
@ -807,6 +865,18 @@ class FPM::Package::Deb < FPM::Package
|
|||
end
|
||||
end
|
||||
|
||||
if dep.start_with?("/")
|
||||
logger.warn("Blanking 'dependency' field '#{dep}' because it's invalid")
|
||||
dep = ""
|
||||
return dep
|
||||
end
|
||||
|
||||
if dep.include?("rpmlib")
|
||||
logger.warn("Blanking 'dependency' field '#{dep}' because it's invalid")
|
||||
dep = ""
|
||||
return dep
|
||||
end
|
||||
|
||||
name_re = /^[^ \(]+/
|
||||
name = dep[name_re]
|
||||
if name =~ /[A-Z]/
|
||||
|
|
@ -900,6 +970,11 @@ class FPM::Package::Deb < FPM::Package
|
|||
provides = provides.gsub("_", "-")
|
||||
end
|
||||
|
||||
if provides.include?("(") and !provides.include?("(=")
|
||||
logger.warn("Blanking 'provides' field '#{provides}' because it's invalid")
|
||||
provides = ""
|
||||
end
|
||||
|
||||
if m = provides.match(/^([A-Za-z0-9_-]+)\s*=\s*(\d+.*$)/)
|
||||
logger.warn("Replacing 'provides' entry #{provides} with syntax 'name (= version)'")
|
||||
provides = "#{m[1]} (= #{m[2]})"
|
||||
|
|
@ -934,12 +1009,21 @@ class FPM::Package::Deb < FPM::Package
|
|||
when "gz", "bzip2", nil
|
||||
controltar = "control.tar.gz"
|
||||
compression_flags = ["-z"]
|
||||
# gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
|
||||
compressor_options = {"GZIP" => "-#{self.attributes[:deb_compression_level] || 9}" +
|
||||
"#{'n' if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?}"}
|
||||
when "xz"
|
||||
controltar = "control.tar.xz"
|
||||
compression_flags = ["-J"]
|
||||
compressor_options = {"XZ_OPT" => "-#{self.attributes[:deb_compression_level] || 3}"}
|
||||
when "zst"
|
||||
controltar = "control.tar.zst"
|
||||
compression_flags = ["--use-compress-program", "zstd"]
|
||||
compressor_options = {"ZSTD_CLEVEL" => "-#{self.attributes[:deb_compression_level] || 3}"}
|
||||
when "none"
|
||||
controltar = "control.tar"
|
||||
compression_flags = []
|
||||
compressor_options = {}
|
||||
else
|
||||
raise FPM::InvalidPackageConfiguration,
|
||||
"Unknown compression type '#{self.attributes[:deb_compression]}'"
|
||||
|
|
@ -954,9 +1038,8 @@ class FPM::Package::Deb < FPM::Package
|
|||
if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?
|
||||
# Force deterministic file order and timestamp
|
||||
args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])]
|
||||
# gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date
|
||||
args.unshift({"GZIP" => "-9n"})
|
||||
end
|
||||
args.unshift(compressor_options)
|
||||
safesystem(*args)
|
||||
end
|
||||
|
||||
|
|
@ -1068,6 +1151,7 @@ class FPM::Package::Deb < FPM::Package
|
|||
logger.debug("Adding config file #{path} to Staging area #{staging_path}")
|
||||
FileUtils.mkdir_p(File.dirname(dcl))
|
||||
FileUtils.cp_r path, dcl
|
||||
add_path(path, allconfigs)
|
||||
else
|
||||
logger.debug("Config file aready exists in staging area.")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -197,10 +197,6 @@ class FPM::Package::Dir < FPM::Package
|
|||
else
|
||||
# Otherwise try copying the file.
|
||||
begin
|
||||
logger.debug("Linking", :source => source, :destination => destination)
|
||||
File.link(source, destination)
|
||||
rescue Errno::ENOENT, Errno::EXDEV, Errno::EPERM
|
||||
# Hardlink attempt failed, copy it instead
|
||||
logger.debug("Copying", :source => source, :destination => destination)
|
||||
copy_entry(source, destination)
|
||||
rescue Errno::EEXIST
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ class FPM::Package::FreeBSD < FPM::Package
|
|||
"Sets the FreeBSD 'origin' pkg field",
|
||||
:default => "fpm/<name>"
|
||||
|
||||
option "--osversion", "VERSION",
|
||||
"Sets the FreeBSD 'version' pkg field, ie 12 or 13, use '*' for all.",
|
||||
:default => "13"
|
||||
|
||||
def output(output_path)
|
||||
output_check(output_path)
|
||||
|
||||
|
|
@ -90,28 +94,36 @@ class FPM::Package::FreeBSD < FPM::Package
|
|||
end # def output
|
||||
|
||||
# Handle architecture naming conversion:
|
||||
# <osname>:<osversion>:<arch>:<wordsize>[.other]
|
||||
# <osname>:<osversion>:<arch>
|
||||
def architecture
|
||||
osname = %x{uname -s}.chomp
|
||||
osversion = %x{uname -r}.chomp.split('.').first
|
||||
osname = 'FreeBSD'
|
||||
|
||||
# Essentially because no testing on other platforms
|
||||
arch = 'x86'
|
||||
|
||||
wordsize = case @architecture
|
||||
arch = case @architecture
|
||||
when nil, 'native'
|
||||
%x{getconf LONG_BIT}.chomp # 'native' is current arch
|
||||
when 'arm64'
|
||||
'64'
|
||||
'arm64'
|
||||
when 'aarch64'
|
||||
'arm64'
|
||||
when 'amd64'
|
||||
'64'
|
||||
'amd64'
|
||||
when 'x86_64'
|
||||
'amd64'
|
||||
when 'i386'
|
||||
'32'
|
||||
'i386'
|
||||
when 'i686'
|
||||
'i386'
|
||||
when 'any'
|
||||
'*'
|
||||
when 'all'
|
||||
'*'
|
||||
when 'noarch'
|
||||
'*'
|
||||
else
|
||||
%x{getconf LONG_BIT}.chomp # default to native, the current arch
|
||||
end
|
||||
|
||||
return [osname, osversion, arch, wordsize].join(':')
|
||||
return [osname, attributes[:freebsd_osversion], arch].join(':')
|
||||
end
|
||||
|
||||
def add_path(tar, tar_path, path)
|
||||
|
|
|
|||
|
|
@ -37,11 +37,15 @@ class FPM::Package::Pacman < FPM::Package
|
|||
def architecture
|
||||
case @architecture
|
||||
when nil
|
||||
return %x{uname -m}.chomp # default to current arch
|
||||
when "amd64" # debian and pacman disagree on architecture names
|
||||
return "x86_64"
|
||||
return %x{uname -m}.chomp # default to current arch
|
||||
when "amd64" # Debian uses amd64
|
||||
return "x86_64" # Arch Linux uses x86_64
|
||||
when "arm64" # Debian uses arm64
|
||||
return "aarch64" # Arch Linux ARM uses aarch64
|
||||
when "armhf" # Debian uses armhf
|
||||
return "arm7hf" # Arch Linux ARM uses arm7hf
|
||||
when "native"
|
||||
return %x{uname -m}.chomp # 'native' is current arch
|
||||
return %x{uname -m}.chomp # 'native' is the current arch
|
||||
when "all", "any", "noarch"
|
||||
return "any"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
#import pkg_resources
|
||||
import packaging.requirements
|
||||
import json
|
||||
import sys
|
||||
|
||||
# Expect requirements lines via stdin.
|
||||
#requirements = pkg_resources.parse_requirements(sys.stdin)
|
||||
|
||||
# Process environment markers, if any, and produce a list of requirements for the current environment.
|
||||
def evaluate_requirements(fd):
|
||||
all_requirements = [packaging.requirements.Requirement(line) for line in sys.stdin]
|
||||
|
||||
for req in all_requirements:
|
||||
# XXX: Note: marker.evaluate() can be given a dict() containing environment values to overwrite
|
||||
if req.marker is None or req.marker.evaluate():
|
||||
if len(req.specifier) > 0:
|
||||
for spec in req.specifier:
|
||||
yield "%s%s" % (req.name, spec)
|
||||
else:
|
||||
yield str(req.name)
|
||||
|
||||
print(json.dumps(list(evaluate_requirements(sys.stdin))))
|
||||
|
|
@ -51,76 +51,371 @@ class FPM::Package::Python < FPM::Package
|
|||
option "--downcase-dependencies", :flag, "Should the package dependencies " \
|
||||
"be in lowercase?", :default => true
|
||||
|
||||
option "--install-bin", "BIN_PATH", "The path to where python scripts " \
|
||||
"should be installed to."
|
||||
option "--install-lib", "LIB_PATH", "The path to where python libs " \
|
||||
option "--install-bin", "BIN_PATH", "(DEPRECATED, does nothing) The path to where python scripts " \
|
||||
"should be installed to." do
|
||||
logger.warn("Using deprecated flag --install-bin")
|
||||
end
|
||||
option "--install-lib", "LIB_PATH", "(DEPRECATED, does nothing) The path to where python libs " \
|
||||
"should be installed to (default depends on your python installation). " \
|
||||
"Want to find out what your target platform is using? Run this: " \
|
||||
"python -c 'from distutils.sysconfig import get_python_lib; " \
|
||||
"print get_python_lib()'"
|
||||
option "--install-data", "DATA_PATH", "The path to where data should be " \
|
||||
"print get_python_lib()'" do
|
||||
logger.warn("Using deprecated flag --install-bin")
|
||||
end
|
||||
|
||||
option "--install-data", "DATA_PATH", "(DEPRECATED, does nothing) The path to where data should be " \
|
||||
"installed to. This is equivalent to 'python setup.py --install-data " \
|
||||
"DATA_PATH"
|
||||
option "--dependencies", :flag, "Include requirements defined in setup.py" \
|
||||
"DATA_PATH" do
|
||||
logger.warn("Using deprecated flag --install-bin")
|
||||
end
|
||||
|
||||
option "--dependencies", :flag, "Include requirements defined by the python package" \
|
||||
" as dependencies.", :default => true
|
||||
option "--obey-requirements-txt", :flag, "Use a requirements.txt file " \
|
||||
"in the top-level directory of the python package for dependency " \
|
||||
"detection.", :default => false
|
||||
option "--scripts-executable", "PYTHON_EXECUTABLE", "Set custom python " \
|
||||
option "--scripts-executable", "PYTHON_EXECUTABLE", "(DEPRECATED) Set custom python " \
|
||||
"interpreter in installing scripts. By default distutils will replace " \
|
||||
"python interpreter in installing scripts (specified by shebang) with " \
|
||||
"current python interpreter (sys.executable). This option is equivalent " \
|
||||
"to appending 'build_scripts --executable PYTHON_EXECUTABLE' arguments " \
|
||||
"to 'setup.py install' command."
|
||||
"to 'setup.py install' command." do
|
||||
logger.warn("Using deprecated flag --install-bin")
|
||||
end
|
||||
|
||||
option "--disable-dependency", "python_package_name",
|
||||
"The python package name to remove from dependency list",
|
||||
:multivalued => true, :attribute_name => :python_disable_dependency,
|
||||
:default => []
|
||||
option "--setup-py-arguments", "setup_py_argument",
|
||||
"Arbitrary argument(s) to be passed to setup.py",
|
||||
"(DEPRECATED) Arbitrary argument(s) to be passed to setup.py",
|
||||
:multivalued => true, :attribute_name => :python_setup_py_arguments,
|
||||
:default => []
|
||||
:default => [] do
|
||||
logger.warn("Using deprecated flag --install-bin")
|
||||
end
|
||||
option "--internal-pip", :flag,
|
||||
"Use the pip module within python to install modules - aka 'python -m pip'. This is the recommended usage since Python 3.4 (2014) instead of invoking the 'pip' script",
|
||||
:attribute_name => :python_internal_pip,
|
||||
:default => true
|
||||
|
||||
class PythonMetadata
|
||||
require "strscan"
|
||||
|
||||
private
|
||||
class MissingField < StandardError; end
|
||||
class UnexpectedContent < StandardError; end
|
||||
|
||||
# According to https://packaging.python.org/en/latest/specifications/core-metadata/
|
||||
# > Core Metadata v2.4 - August 2024
|
||||
MULTIPLE_USE = %w(Dynamic Platform Supported-Platform License-File Classifier Requires-Dist Requires-External Project-URL Provides-Extra Provides-Dist Obsoletes-Dist)
|
||||
|
||||
# METADATA files are described in Python Packaging "Core Metadata"[1] and appear to have roughly RFC822 syntax.
|
||||
# [1] https://packaging.python.org/en/latest/specifications/core-metadata/#core-metadata
|
||||
def self.parse(input)
|
||||
s = StringScanner.new(input)
|
||||
headers = {}
|
||||
|
||||
# Default "Multiple use" fields to empty array instead of nil.
|
||||
MULTIPLE_USE.each do |field|
|
||||
headers[field] = []
|
||||
end
|
||||
|
||||
while !s.eos? and !s.scan("\n") do
|
||||
# Field is non-space up, but excluding the colon
|
||||
field = s.scan(/[^\s:]+/)
|
||||
|
||||
# Skip colon and following whitespace
|
||||
s.scan(/:\s*/)
|
||||
|
||||
# Value is text until newline, and any following lines if they have leading spaces.
|
||||
value = s.scan(/[^\n]+(?:\Z|\n(?:[ \t][^\n]+\n)*)/)
|
||||
if value.nil?
|
||||
raise "Failed parsing Python package metadata value at field #{field}, char offset #{s.pos}"
|
||||
end
|
||||
value = value.chomp
|
||||
|
||||
if MULTIPLE_USE.include?(field)
|
||||
raise "Header field should be an array. This is a bug in fpm." if !headers[field].is_a?(Array)
|
||||
headers[field] << value
|
||||
else
|
||||
headers[field] = value
|
||||
end
|
||||
end # while reading headers
|
||||
|
||||
# If there's more content beyond the last header, then it's a content body.
|
||||
# In Python Metadata >= 2.1, the descriptino can be written in the body.
|
||||
if !s.eos?
|
||||
if headers["Metadata-Version"].to_f >= 2.1
|
||||
# Per Python core-metadata spec:
|
||||
# > Changed in version 2.1: This field may be specified in the message body instead.
|
||||
#return PythonMetadata.new(headers, s.string[s.pos ...])
|
||||
return headers, s.string[s.pos ... ]
|
||||
elsif headers["Metadata-Version"].to_f >= 2.0
|
||||
# dnspython v1.15.0 has a description body and Metadata-Version 2.0
|
||||
# this seems out of spec, but let's accept it anyway.
|
||||
return headers, s.string[s.pos ... ]
|
||||
else
|
||||
raise "After reading METADATA headers, extra data is in the file but was not expected. This may be a bug in fpm."
|
||||
end
|
||||
end
|
||||
|
||||
#return PythonMetadata.new(headers)
|
||||
return headers, nil # nil means no body in this metadata
|
||||
rescue => e
|
||||
puts "String scan failed: #{e}"
|
||||
puts "Position: #{s.pointer}"
|
||||
puts "---"
|
||||
puts input
|
||||
puts "==="
|
||||
puts input[s.pointer...]
|
||||
puts "---"
|
||||
raise e
|
||||
end # self.parse
|
||||
|
||||
def self.from(input)
|
||||
return PythonMetadata.new(*parse(input))
|
||||
end
|
||||
|
||||
# Only focusing on terms fpm may care about
|
||||
attr_reader :name, :version, :summary, :description, :keywords, :maintainer, :license, :requires, :homepage
|
||||
|
||||
FIELD_MAP = {
|
||||
:@name => "Name",
|
||||
:@version => "Version",
|
||||
:@summary => "Summary",
|
||||
:@description => "Description",
|
||||
:@keywords => "Keywords",
|
||||
:@maintainer => "Author-email",
|
||||
|
||||
# Note: License can also come from the deprecated "License" field
|
||||
# This is processed later in this method.
|
||||
:@license => "License-Expression",
|
||||
|
||||
:@requires => "Requires-Dist",
|
||||
}
|
||||
|
||||
REQUIRED_FIELDS = [ "Metadata-Version", "Name", "Version" ]
|
||||
|
||||
# headers - a Hash containing field-value pairs from headers as read from a python METADATA file.
|
||||
# body - optional, a string containing the body text of a METADATA file
|
||||
def initialize(headers, body=nil)
|
||||
REQUIRED_FIELDS.each do |field|
|
||||
if !headers.include?(field)
|
||||
raise MissingField, "Missing required Python metadata field, '#{field}'. This might be a bug in the package or in fpm."
|
||||
end
|
||||
end
|
||||
|
||||
FIELD_MAP.each do |attr, field|
|
||||
if headers.include?(field)
|
||||
instance_variable_set(attr, headers.fetch(field))
|
||||
end
|
||||
end
|
||||
|
||||
# Do any extra processing on fields to turn them into their expected content.
|
||||
process_description(headers, body)
|
||||
process_license(headers)
|
||||
process_homepage(headers)
|
||||
process_maintainer(headers)
|
||||
end # def initialize
|
||||
|
||||
private
|
||||
def process_description(headers, body)
|
||||
if @description
|
||||
# Per python core-metadata spec:
|
||||
# > To support empty lines and lines with indentation with respect to the
|
||||
# > RFC 822 format, any CRLF character has to be suffixed by 7 spaces
|
||||
# > followed by a pipe (“|”) char. As a result, the Description field is
|
||||
# > encoded into a folded field that can be interpreted by RFC822 parser [2].
|
||||
@description = @description.gsub!(/^ |/, "")
|
||||
end
|
||||
|
||||
if !body.nil?
|
||||
if headers["Metadata-Version"].to_f >= 2.1
|
||||
# Per Python core-metadata spec:
|
||||
# > Changed in version 2.1: [Description] field may be specified in the message body instead.
|
||||
#
|
||||
# The description is simply the rest of the METADATA file after the headers.
|
||||
@description = body
|
||||
elsif headers["Metadata-Version"].to_f >= 2.0
|
||||
# dnspython v1.15.0 has a description body and Metadata-Version 2.0
|
||||
# this seems out of spec, but let's accept it anyway.
|
||||
@description = body
|
||||
else
|
||||
raise UnexpectedContent, "Found a content body in METADATA file, but Metadata-Version(#{headers["Metadata-Version"]}) is below 2.1 and doesn't support this. This may be a bug in fpm or a malformed python package."
|
||||
end
|
||||
|
||||
# What to do if we find a description body but already have a Description field set in the headers?
|
||||
if headers.include?("Description")
|
||||
raise "Found a description in the body of the python package metadata, but the package already set the Description field. I don't know what to do. This is probably a bug in fpm."
|
||||
end
|
||||
end
|
||||
|
||||
# XXX: The description field can be markdown, plain text, or reST.
|
||||
# Content type is noted in the "Description-Content-Type" field
|
||||
# Should we transform this to plain text?
|
||||
end # process_description
|
||||
|
||||
def process_license(headers)
|
||||
# Ignore the "License" field if License-Expression is also present.
|
||||
return if headers["Metadata-Version"].to_f >= 2.4 && headers.include?("License-Expression")
|
||||
|
||||
# Deprecated field, License, as described in python core-metadata:
|
||||
# > As of Metadata 2.4, License and License-Expression are mutually exclusive.
|
||||
# > If both are specified, tools which parse metadata will disregard License
|
||||
# > and PyPI will reject uploads. See PEP 639.
|
||||
if headers["License"]
|
||||
# Note: This license can be free form text, so it's unclear if it's a great choice.
|
||||
# however, the original python metadata License field is quite old/deprecated
|
||||
# so maybe nobody uses it anymore?
|
||||
@license = headers["License"]
|
||||
elsif license_classifier = headers["Classifier"].find { |value| value =~ /^License ::/ }
|
||||
# The license could also show up in the "Classifier" header with "License ::" as a prefix.
|
||||
@license = license_classifier.sub(/^License ::/, "")
|
||||
end # check for deprecated License field
|
||||
end # process_license
|
||||
|
||||
def process_homepage(headers)
|
||||
return if headers["Project-URL"].empty?
|
||||
|
||||
# Create a hash of Project-URL where the label is the key, url the value.
|
||||
urls = Hash[*headers["Project-URL"].map do |text|
|
||||
label, url = text.split(/, */, 2)
|
||||
# Normalize the label by removing punctuation and spaces
|
||||
# Reference: https://packaging.python.org/en/latest/specifications/well-known-project-urls/#label-normalization
|
||||
# > In plain language: a label is normalized by deleting all ASCII punctuation and whitespace, and then converting the result to lowercase.
|
||||
label = label.gsub(/[[:punct:][:space:]]/, "").downcase
|
||||
[label, url]
|
||||
end.flatten(1)]
|
||||
|
||||
# Prioritize certain URL labels when choosing the homepage url.
|
||||
[ "homepage", "source", "documentation", "releasenotes" ].each do |label|
|
||||
if urls.include?(label)
|
||||
@homepage = urls[label]
|
||||
end
|
||||
end
|
||||
|
||||
# Otherwise, default to the first URL
|
||||
@homepage = urls.values.first
|
||||
end
|
||||
|
||||
def process_maintainer(headers)
|
||||
# Python metadata supports both "Author-email" and "Maintainer-email"
|
||||
# Of the "Maintainer" fields, python core-metadata says:
|
||||
# > Note that this field is intended for use when a project is being maintained by someone other than the original author
|
||||
#
|
||||
# So we should prefer Maintainer-email if it exists, but fall back to Author-email otherwise.
|
||||
@maintainer = headers["Maintainer-email"] unless headers["Maintainer-email"].nil?
|
||||
end
|
||||
end # class PythonMetadata
|
||||
|
||||
# Input a package.
|
||||
#
|
||||
# The 'package' can be any of:
|
||||
#
|
||||
# * A name of a package on pypi (ie; easy_install some-package)
|
||||
# * The path to a directory containing setup.py
|
||||
# * The path to a setup.py
|
||||
# * The path to a directory containing setup.py or pyproject.toml
|
||||
# * The path to a setup.py or pyproject.toml
|
||||
# * The path to a python sdist file ending in .tar.gz
|
||||
# * The path to a python wheel file ending in .whl
|
||||
def input(package)
|
||||
explore_environment
|
||||
|
||||
path_to_package = download_if_necessary(package, version)
|
||||
|
||||
# Expect a setup.py or pyproject.toml if it's a directory.
|
||||
if File.directory?(path_to_package)
|
||||
setup_py = File.join(path_to_package, "setup.py")
|
||||
else
|
||||
setup_py = path_to_package
|
||||
if !(File.exist?(File.join(path_to_package, "setup.py")) or File.exist?(File.join(path_to_package, "pyproject.toml")))
|
||||
raise FPM::InvalidPackageConfiguration, "The path ('#{path_to_package}') doesn't appear to be a python package directory. I expected either a pyproject.toml or setup.py but found neither."
|
||||
end
|
||||
end
|
||||
|
||||
if !File.exist?(setup_py)
|
||||
logger.error("Could not find 'setup.py'", :path => setup_py)
|
||||
raise "Unable to find python package; tried #{setup_py}"
|
||||
if File.file?(path_to_package)
|
||||
if ["setup.py", "pyproject.toml"].include?(File.basename(path_to_package))
|
||||
path_to_package = File.dirname(path_to_package)
|
||||
end
|
||||
end
|
||||
|
||||
load_package_info(setup_py)
|
||||
install_to_staging(setup_py)
|
||||
if [".tar.gz", ".tgz"].any? { |suffix| path_to_package.end_with?(suffix) }
|
||||
# Have pip convert the .tar.gz (source dist?) into a wheel
|
||||
logger.debug("Found tarball and assuming it's a python source package.")
|
||||
safesystem(*attributes[:python_pip], "wheel", "--no-deps", "-w", build_path, path_to_package)
|
||||
|
||||
path_to_package = ::Dir.glob(build_path("*.whl")).first
|
||||
if path_to_package.nil?
|
||||
raise FPM::InvalidPackageConfiguration, "Failed building python package format - fpm tried to build a python wheel, but didn't find the .whl file. This might be a bug in fpm."
|
||||
end
|
||||
elsif File.directory?(path_to_package)
|
||||
logger.debug("Found directory and assuming it's a python source package.")
|
||||
safesystem(*attributes[:python_pip], "wheel", "--no-deps", "-w", build_path, path_to_package)
|
||||
|
||||
if attributes[:python_obey_requirements_txt?]
|
||||
reqtxt = File.join(path_to_package, "requirements.txt")
|
||||
@requirements_txt = File.read(reqtxt).split("\n") if File.file?(reqtxt)
|
||||
end
|
||||
|
||||
path_to_package = ::Dir.glob(build_path("*.whl")).first
|
||||
if path_to_package.nil?
|
||||
raise FPM::InvalidPackageConfiguration, "Failed building python package format - fpm tried to build a python wheel, but didn't find the .whl file. This might be a bug in fpm."
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load_package_info(path_to_package)
|
||||
install_to_staging(path_to_package)
|
||||
end # def input
|
||||
|
||||
def explore_environment
|
||||
if !attributes[:python_bin_given?]
|
||||
# If --python-bin isn't set, try to find a good default python executable path, because it might not be "python"
|
||||
pythons = [ "python", "python3", "python2" ]
|
||||
default_python = pythons.find { |py| program_exists?(py) }
|
||||
|
||||
if default_python.nil?
|
||||
raise FPM::Util::ExecutableNotFound, "Could not find any python interpreter. Tried the following: #{pythons.join(", ")}"
|
||||
end
|
||||
|
||||
logger.info("Setting default python executable", :name => default_python)
|
||||
attributes[:python_bin] = default_python
|
||||
|
||||
if !attributes[:python_package_name_prefix_given?]
|
||||
attributes[:python_package_name_prefix] = default_python
|
||||
logger.info("Setting package name prefix", :name => default_python)
|
||||
end
|
||||
end
|
||||
|
||||
if attributes[:python_internal_pip?]
|
||||
# XXX: Should we detect if internal pip is available?
|
||||
attributes[:python_pip] = [ attributes[:python_bin], "-m", "pip"]
|
||||
end
|
||||
end # explore_environment
|
||||
|
||||
|
||||
|
||||
# Download the given package if necessary. If version is given, that version
|
||||
# will be downloaded, otherwise the latest is fetched.
|
||||
def download_if_necessary(package, version=nil)
|
||||
# TODO(sissel): this should just be a 'download' method, the 'if_necessary'
|
||||
# part should go elsewhere.
|
||||
path = package
|
||||
|
||||
# If it's a path, assume local build.
|
||||
if File.directory?(path) or (File.exist?(path) and File.basename(path) == "setup.py")
|
||||
return path
|
||||
if File.exist?(path)
|
||||
return path if File.directory?(path)
|
||||
|
||||
basename = File.basename(path)
|
||||
return File.dirname(path) if basename == "pyproject.toml"
|
||||
return File.dirname(path) if basename == "setup.py"
|
||||
|
||||
return path if path.end_with?(".tar.gz")
|
||||
return path if path.end_with?(".tgz") # amqplib v1.0.2 does this
|
||||
return path if path.end_with?(".whl")
|
||||
return path if path.end_with?(".zip")
|
||||
return path if File.exist?(File.join(path, "setup.py"))
|
||||
return path if File.exist?(File.join(path, "pyproject.toml"))
|
||||
|
||||
raise [
|
||||
"Local file doesn't appear to be a supported type for a python package. Expected one of:",
|
||||
" - A directory containing setup.py or pyproject.toml",
|
||||
" - A file ending in .tar.gz (a python source dist)",
|
||||
" - A file ending in .whl (a python wheel)",
|
||||
].join("\n")
|
||||
end
|
||||
|
||||
logger.info("Trying to download", :package => package)
|
||||
|
|
@ -134,24 +429,16 @@ class FPM::Package::Python < FPM::Package
|
|||
target = build_path(package)
|
||||
FileUtils.mkdir(target) unless File.directory?(target)
|
||||
|
||||
if attributes[:python_internal_pip?]
|
||||
# XXX: Should we detect if internal pip is available?
|
||||
attributes[:python_pip] = [ attributes[:python_bin], "-m", "pip"]
|
||||
end
|
||||
|
||||
# attributes[:python_pip] -- expected to be a path
|
||||
if attributes[:python_pip]
|
||||
logger.debug("using pip", :pip => attributes[:python_pip])
|
||||
# TODO: Support older versions of pip
|
||||
|
||||
pip = [attributes[:python_pip]] if pip.is_a?(String)
|
||||
setup_cmd = [
|
||||
*attributes[:python_pip],
|
||||
"download",
|
||||
"--no-clean",
|
||||
"--no-deps",
|
||||
"--no-binary", ":all:",
|
||||
"-d", build_path,
|
||||
"-d", target,
|
||||
"-i", attributes[:python_pypi],
|
||||
]
|
||||
|
||||
|
|
@ -166,124 +453,105 @@ class FPM::Package::Python < FPM::Package
|
|||
|
||||
safesystem(*setup_cmd)
|
||||
|
||||
# Pip removed the --build flag sometime in 2021, it seems: https://github.com/pypa/pip/issues/8333
|
||||
# A workaround for pip removing the `--build` flag. Previously, `pip download --build ...` would leave
|
||||
# behind a directory with the Python package extracted and ready to be used.
|
||||
# For example, `pip download ... Django` puts `Django-4.0.4.tar.tz` into the build_path directory.
|
||||
# If we expect `pip` to leave an unknown-named file in the `build_path` directory, let's check for
|
||||
# a single file and unpack it. I don't know if it will /always/ be a .tar.gz though.
|
||||
files = ::Dir.glob(File.join(build_path, "*.tar.gz"))
|
||||
files = ::Dir.entries(target).filter { |entry| entry =~ /\.(whl|tgz|tar\.gz|zip)$/ }
|
||||
if files.length != 1
|
||||
raise "Unexpected directory layout after `pip download ...`. This might be an fpm bug? The directory is #{build_path}"
|
||||
raise "Unexpected directory layout after `pip download ...`. This might be an fpm bug? The directory contains these files: #{files.inspect}"
|
||||
end
|
||||
|
||||
safesystem("tar", "-zxf", files[0], "-C", target)
|
||||
return File.join(target, files.first)
|
||||
else
|
||||
# no pip, use easy_install
|
||||
logger.debug("no pip, defaulting to easy_install", :easy_install => attributes[:python_easyinstall])
|
||||
safesystem(attributes[:python_easyinstall], "-i",
|
||||
attributes[:python_pypi], "--editable", "-U",
|
||||
"--build-directory", target, want_pkg)
|
||||
# easy_install will put stuff in @tmpdir/packagename/, so find that:
|
||||
# @tmpdir/somepackage/setup.py
|
||||
#dirs = ::Dir.glob(File.join(target, "*"))
|
||||
files = ::Dir.entries(target).filter { |entry| entry != "." && entry != ".." }
|
||||
if dirs.length != 1
|
||||
raise "Unexpected directory layout after easy_install. Maybe file a bug? The directory is #{build_path}"
|
||||
end
|
||||
return dirs.first
|
||||
end
|
||||
|
||||
# easy_install will put stuff in @tmpdir/packagename/, so find that:
|
||||
# @tmpdir/somepackage/setup.py
|
||||
dirs = ::Dir.glob(File.join(target, "*"))
|
||||
if dirs.length != 1
|
||||
raise "Unexpected directory layout after easy_install. Maybe file a bug? The directory is #{build_path}"
|
||||
end
|
||||
return dirs.first
|
||||
end # def download
|
||||
|
||||
# Load the package information like name, version, dependencies.
|
||||
def load_package_info(setup_py)
|
||||
if !attributes[:python_package_prefix].nil?
|
||||
attributes[:python_package_name_prefix] = attributes[:python_package_prefix]
|
||||
end
|
||||
|
||||
begin
|
||||
json_test_code = [
|
||||
"try:",
|
||||
" import json",
|
||||
"except ImportError:",
|
||||
" import simplejson as json"
|
||||
].join("\n")
|
||||
safesystem("#{attributes[:python_bin]} -c '#{json_test_code}'")
|
||||
rescue FPM::Util::ProcessFailed => e
|
||||
logger.error("Your python environment is missing json support (either json or simplejson python module). I cannot continue without this.", :python => attributes[:python_bin], :error => e)
|
||||
raise FPM::Util::ProcessFailed, "Python (#{attributes[:python_bin]}) is missing simplejson or json modules."
|
||||
end
|
||||
|
||||
begin
|
||||
safesystem("#{attributes[:python_bin]} -c 'import pkg_resources'")
|
||||
rescue FPM::Util::ProcessFailed => e
|
||||
logger.error("Your python environment is missing a working setuptools module. I tried to find the 'pkg_resources' module but failed.", :python => attributes[:python_bin], :error => e)
|
||||
raise FPM::Util::ProcessFailed, "Python (#{attributes[:python_bin]}) is missing pkg_resources module."
|
||||
end
|
||||
|
||||
# Add ./pyfpm/ to the python library path
|
||||
pylib = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
# chdir to the directory holding setup.py because some python setup.py's assume that you are
|
||||
# in the same directory.
|
||||
setup_dir = File.dirname(setup_py)
|
||||
|
||||
output = ::Dir.chdir(setup_dir) do
|
||||
tmp = build_path("metadata.json")
|
||||
setup_cmd = "env PYTHONPATH=#{pylib}:$PYTHONPATH #{attributes[:python_bin]} " \
|
||||
"setup.py --command-packages=pyfpm get_metadata --output=#{tmp}"
|
||||
|
||||
if attributes[:python_obey_requirements_txt?]
|
||||
setup_cmd += " --load-requirements-txt"
|
||||
def load_package_info(path)
|
||||
if path.end_with?(".whl")
|
||||
# XXX: Maybe use rubyzip to parse the .whl (zip) file instead?
|
||||
metadata = nil
|
||||
execmd(["unzip", "-p", path, "*.dist-info/METADATA"], :stdin => false, :stderr => false) do |stdout|
|
||||
metadata = PythonMetadata.from(stdout.read(64<<10))
|
||||
end
|
||||
|
||||
# Capture the output, which will be JSON metadata describing this python
|
||||
# package. See fpm/lib/fpm/package/pyfpm/get_metadata.py for more
|
||||
# details.
|
||||
logger.info("fetching package metadata", :setup_cmd => setup_cmd)
|
||||
|
||||
success = safesystem(setup_cmd)
|
||||
#%x{#{setup_cmd}}
|
||||
if !success
|
||||
logger.error("setup.py get_metadata failed", :command => setup_cmd,
|
||||
:exitcode => $?.exitstatus)
|
||||
raise "An unexpected error occurred while processing the setup.py file"
|
||||
wheeldata = nil
|
||||
execmd(["unzip", "-p", path, "*.dist-info/WHEEL"], :stdin => false, :stderr => false) do |stdout|
|
||||
wheeldata, _ = PythonMetadata.parse(stdout.read(64<<10))
|
||||
end
|
||||
File.read(tmp)
|
||||
else
|
||||
raise "Unexpected python package path. This might be an fpm bug? The path is #{path}"
|
||||
end
|
||||
logger.debug("result from `setup.py get_metadata`", :data => output)
|
||||
metadata = JSON.parse(output)
|
||||
logger.info("object output of get_metadata", :json => metadata)
|
||||
|
||||
self.architecture = metadata["architecture"]
|
||||
self.description = metadata["description"]
|
||||
# Sometimes the license field is multiple lines; do best-effort and just
|
||||
# use the first line.
|
||||
if metadata["license"]
|
||||
self.license = metadata["license"].split(/[\r\n]+/).first
|
||||
end
|
||||
self.version = metadata["version"]
|
||||
self.url = metadata["url"]
|
||||
self.architecture = wheeldata["Root-Is-Purelib"] == "true" ? "all" : "native"
|
||||
|
||||
self.description = metadata.description unless metadata.description.nil?
|
||||
self.license = metadata.license unless metadata.license.nil?
|
||||
self.version = metadata.version
|
||||
self.url = metadata.homepage unless metadata.homepage.nil?
|
||||
|
||||
self.name = metadata.name
|
||||
|
||||
# name prefixing is optional, if enabled, a name 'foo' will become
|
||||
# 'python-foo' (depending on what the python_package_name_prefix is)
|
||||
if attributes[:python_fix_name?]
|
||||
self.name = fix_name(metadata["name"])
|
||||
else
|
||||
self.name = metadata["name"]
|
||||
end
|
||||
self.name = fix_name(self.name) if attributes[:python_fix_name?]
|
||||
|
||||
# convert python-Foo to python-foo if flag is set
|
||||
self.name = self.name.downcase if attributes[:python_downcase_name?]
|
||||
|
||||
self.maintainer = metadata.maintainer
|
||||
|
||||
if !attributes[:no_auto_depends?] and attributes[:python_dependencies?]
|
||||
metadata["dependencies"].each do |dep|
|
||||
dep_re = /^([^<>!= ]+)\s*(?:([~<>!=]{1,2})\s*(.*))?$/
|
||||
# Python Dependency specifiers are a somewhat complex format described here:
|
||||
# https://packaging.python.org/en/latest/specifications/dependency-specifiers/#environment-markers
|
||||
#
|
||||
# We can ask python's packaging module to parse and evaluate these.
|
||||
# XXX: Allow users to override environnment values.
|
||||
#
|
||||
# Example:
|
||||
# Requires-Dist: tzdata; sys_platform = win32
|
||||
# Requires-Dist: asgiref>=3.8.1
|
||||
|
||||
dep_re = /^([^<>!= ]+)\s*(?:([~<>!=]{1,2})\s*(.*))?$/
|
||||
|
||||
reqs = []
|
||||
|
||||
# --python-obey-requirements-txt should use requirements.txt
|
||||
# (if found in the python package) and replace the requirments listed from the metadata
|
||||
if attributes[:python_obey_requirements_txt?] && !@requirements_txt.nil?
|
||||
requires = @requirements_txt
|
||||
else
|
||||
requires = metadata.requires
|
||||
end
|
||||
|
||||
# Evaluate python package requirements and only show ones matching the current environment
|
||||
# (Environment markers, etc)
|
||||
# Additionally, 'extra' features such as a requirement named `django[bcrypt]` isn't quite supported yet,
|
||||
# since the marker.evaluate() needs to be passed some environment like { "extra": "bcrypt" }
|
||||
execmd([attributes[:python_bin], File.expand_path(File.join("pyfpm", "parse_requires.py"), File.dirname(__FILE__))]) do |stdin, stdout, stderr|
|
||||
requires.each { |r| stdin.puts(r) }
|
||||
stdin.close
|
||||
data = stdout.read
|
||||
logger.pipe(stderr => :warn)
|
||||
reqs += JSON.parse(data)
|
||||
end
|
||||
|
||||
reqs.each do |dep|
|
||||
match = dep_re.match(dep)
|
||||
if match.nil?
|
||||
logger.error("Unable to parse dependency", :dependency => dep)
|
||||
raise FPM::InvalidPackageConfiguration, "Invalid dependency '#{dep}'"
|
||||
end
|
||||
|
||||
name, cmp, version = match.captures
|
||||
|
||||
next if attributes[:python_disable_dependency].include?(name)
|
||||
|
|
@ -302,8 +570,12 @@ class FPM::Package::Python < FPM::Package
|
|||
# convert dependencies from python-Foo to python-foo
|
||||
name = name.downcase if attributes[:python_downcase_dependencies?]
|
||||
|
||||
self.dependencies << "#{name} #{cmp} #{version}"
|
||||
end
|
||||
if cmp.nil? && version.nil?
|
||||
self.dependencies << "#{name}"
|
||||
else
|
||||
self.dependencies << "#{name} #{cmp} #{version}"
|
||||
end
|
||||
end # parse Requires-Dist dependencies
|
||||
end # if attributes[:python_dependencies?]
|
||||
end # def load_package_info
|
||||
|
||||
|
|
@ -323,55 +595,17 @@ class FPM::Package::Python < FPM::Package
|
|||
end # def fix_name
|
||||
|
||||
# Install this package to the staging directory
|
||||
def install_to_staging(setup_py)
|
||||
project_dir = File.dirname(setup_py)
|
||||
|
||||
def install_to_staging(path)
|
||||
prefix = "/"
|
||||
prefix = attributes[:prefix] unless attributes[:prefix].nil?
|
||||
|
||||
# Some setup.py's assume $PWD == current directory of setup.py, so let's
|
||||
# chdir first.
|
||||
::Dir.chdir(project_dir) do
|
||||
flags = [ "--root", staging_path ]
|
||||
if !attributes[:python_install_lib].nil?
|
||||
flags += [ "--install-lib", File.join(prefix, attributes[:python_install_lib]) ]
|
||||
elsif !attributes[:prefix].nil?
|
||||
# setup.py install --prefix PREFIX still installs libs to
|
||||
# PREFIX/lib64/python2.7/site-packages/
|
||||
# but we really want something saner.
|
||||
#
|
||||
# since prefix is given, but not python_install_lib, assume PREFIX/lib
|
||||
flags += [ "--install-lib", File.join(prefix, "lib") ]
|
||||
end
|
||||
# XXX: Note: pip doesn't seem to have any equivalent to `--install-lib` or similar flags.
|
||||
# XXX: Deprecate :python_install_data, :python_install_lib, :python_install_bin
|
||||
# XXX: Deprecate: :python_setup_py_arguments
|
||||
flags = [ "--root", staging_path ]
|
||||
flags += [ "--prefix", prefix ] if !attributes[:prefix].nil?
|
||||
|
||||
if !attributes[:python_install_data].nil?
|
||||
flags += [ "--install-data", File.join(prefix, attributes[:python_install_data]) ]
|
||||
elsif !attributes[:prefix].nil?
|
||||
# prefix given, but not python_install_data, assume PREFIX/data
|
||||
flags += [ "--install-data", File.join(prefix, "data") ]
|
||||
end
|
||||
|
||||
if !attributes[:python_install_bin].nil?
|
||||
flags += [ "--install-scripts", File.join(prefix, attributes[:python_install_bin]) ]
|
||||
elsif !attributes[:prefix].nil?
|
||||
# prefix given, but not python_install_bin, assume PREFIX/bin
|
||||
flags += [ "--install-scripts", File.join(prefix, "bin") ]
|
||||
end
|
||||
|
||||
if !attributes[:python_scripts_executable].nil?
|
||||
# Overwrite installed python scripts shebang binary with provided executable
|
||||
flags += [ "build_scripts", "--executable", attributes[:python_scripts_executable] ]
|
||||
end
|
||||
|
||||
if !attributes[:python_setup_py_arguments].nil? and !attributes[:python_setup_py_arguments].empty?
|
||||
# Add optional setup.py arguments
|
||||
attributes[:python_setup_py_arguments].each do |a|
|
||||
flags += [ a ]
|
||||
end
|
||||
end
|
||||
|
||||
safesystem(attributes[:python_bin], "setup.py", "install", *flags)
|
||||
end
|
||||
safesystem(*attributes[:python_pip], "install", "--no-deps", *flags, path)
|
||||
end # def install_to_staging
|
||||
|
||||
public(:input)
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ class FPM::Package::RPM < FPM::Package
|
|||
|
||||
option "--macro-expansion", :flag,
|
||||
"install-time macro expansion in %pre %post %preun %postun scripts " \
|
||||
"(see: https://rpm.org/user_doc/scriptlet_expansion.html)", :default => false
|
||||
"(see: https://rpm-software-management.github.io/rpm/manual/scriptlet_expansion.html)", :default => false
|
||||
|
||||
option "--verifyscript", "FILE",
|
||||
"a script to be run on verification" do |val|
|
||||
|
|
@ -175,7 +175,7 @@ class FPM::Package::RPM < FPM::Package
|
|||
rpm_trigger = []
|
||||
option "--trigger-#{trigger_type}", "'[OPT]PACKAGE: FILEPATH'", "Adds a rpm trigger script located in FILEPATH, " \
|
||||
"having 'OPT' options and linking to 'PACKAGE'. PACKAGE can be a comma seperated list of packages. " \
|
||||
"See: http://rpm.org/api/4.4.2.2/triggers.html" do |trigger|
|
||||
"See: https://rpm-software-management.github.io/rpm/manual/triggers.html" do |trigger|
|
||||
match = trigger.match(/^(\[.*\]|)(.*): (.*)$/)
|
||||
@logger.fatal("Trigger '#{trigger_type}' definition can't be parsed ('#{trigger}')") unless match
|
||||
opt, pkg, file = match.captures
|
||||
|
|
@ -185,6 +185,9 @@ class FPM::Package::RPM < FPM::Package
|
|||
end
|
||||
end
|
||||
|
||||
option "--old-perl-dependency-name", :flag,
|
||||
"Use older 'perl' depdency name. Newer Red Hat (and derivatives) use a dependency named 'perl-interpreter'."
|
||||
|
||||
private
|
||||
|
||||
# Fix path name
|
||||
|
|
@ -196,8 +199,8 @@ class FPM::Package::RPM < FPM::Package
|
|||
# If and only if any of the above are done, then also replace ' with \', " with \", and \ with \\\\
|
||||
# to accommodate escape and quote processing that rpm will perform in that case (but not otherwise)
|
||||
def rpm_fix_name(name)
|
||||
if name.match?(/[ \t*?%$\[\]]/)
|
||||
name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\\)/, {
|
||||
if name.match?(/[ \t*?%${}\[\]]/)
|
||||
name = name.gsub(/(\ |\t|\[|\]|\*|\?|\%|\$|'|"|\{|\}|\\)/, {
|
||||
' ' => '?',
|
||||
"\t" => '?',
|
||||
'%' => '[%]',
|
||||
|
|
@ -206,6 +209,10 @@ class FPM::Package::RPM < FPM::Package
|
|||
'*' => '[*]',
|
||||
'[' => '[\[]',
|
||||
']' => '[\]]',
|
||||
#'{' => '[\{]',
|
||||
#'}' => '[\}]',
|
||||
'{' => '?',
|
||||
'}' => '?',
|
||||
'"' => '\\"',
|
||||
"'" => "\\'",
|
||||
'\\' => '\\\\\\\\',
|
||||
|
|
@ -275,9 +282,41 @@ class FPM::Package::RPM < FPM::Package
|
|||
return @iteration ? @iteration : 1
|
||||
end # def iteration
|
||||
|
||||
# Generate a generic changelog or return an existing definition
|
||||
def changelog
|
||||
if attributes[:rpm_changelog]
|
||||
return attributes[:rpm_changelog]
|
||||
end
|
||||
|
||||
reldate = if attributes[:source_date_epoch].nil?
|
||||
Time.now()
|
||||
else
|
||||
Time.at(attributes[:source_date_epoch].to_i)
|
||||
end
|
||||
changed = reldate.strftime("%a %b %_e %Y")
|
||||
changev = "#{version}-#{iteration}"
|
||||
changev += "%{?dist}" if attributes[:rpm_dist]
|
||||
|
||||
"* #{changed} #{maintainer} - #{changev}\n- Package created with FPM\n"
|
||||
end
|
||||
|
||||
# See FPM::Package#converted_from
|
||||
def converted_from(origin)
|
||||
if origin == FPM::Package::Gem
|
||||
if origin == FPM::Package::CPAN
|
||||
if !attributes[:rpm_old_perl_dependency_name?]
|
||||
fixed_deps = []
|
||||
self.dependencies.collect do |dep|
|
||||
# RPM package "perl" is a metapackage which install all the Perl bits and core modules, then gcc...
|
||||
# this must be replaced by perl-interpreter
|
||||
if name=/^perl([\s<>=].*)$/.match(dep)
|
||||
fixed_deps.push("perl-interpreter#{name[1]}")
|
||||
else
|
||||
fixed_deps.push(dep)
|
||||
end
|
||||
end
|
||||
self.dependencies = fixed_deps
|
||||
end
|
||||
elsif origin == FPM::Package::Gem
|
||||
fixed_deps = []
|
||||
self.dependencies.collect do |dep|
|
||||
# Gem dependency operator "~>" is not compatible with rpm. Translate any found.
|
||||
|
|
@ -473,6 +512,7 @@ class FPM::Package::RPM < FPM::Package
|
|||
args += ["--define", "dist .#{attributes[:rpm_dist]}"] if attributes[:rpm_dist]
|
||||
|
||||
args += [
|
||||
"--buildroot", "#{build_path}/BUILD",
|
||||
"--define", "buildroot #{build_path}/BUILD",
|
||||
"--define", "_topdir #{build_path}",
|
||||
"--define", "_sourcedir #{build_path}",
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class FPM::Package::Virtualenv < FPM::Package
|
|||
:default => nil
|
||||
|
||||
option "--setup-install", :flag, "After building virtualenv run setup.py install "\
|
||||
"useful when building a virtualenv for packages and including their requirements from "
|
||||
"useful when building a virtualenv for packages and including their requirements from "\
|
||||
"requirements.txt"
|
||||
|
||||
option "--system-site-packages", :flag, "Give the virtual environment access to the "\
|
||||
|
|
@ -158,6 +158,31 @@ class FPM::Package::Virtualenv < FPM::Package
|
|||
end
|
||||
end
|
||||
|
||||
# [2025-09-30] virtualenv-tools seems broken?
|
||||
# The --update-path will look for a VIRTUAL_ENV= line in bin/activate,
|
||||
# however, the version I tested looks for it with quotations, like VIRTUAL_ENV='
|
||||
# And at time of writing, my `virtualenv` tool doesn't use quotations on this variable
|
||||
#
|
||||
# Maybe best case we can patch it here instead. The path update tool
|
||||
# looks for the original virtualenv path and I think updates any bin
|
||||
# files which point to it.
|
||||
patched = []
|
||||
activate_bin = File.join(virtualenv_build_folder, "bin/activate")
|
||||
fd = File.open(activate_bin)
|
||||
fd.each_line do |line|
|
||||
re = /^VIRTUAL_ENV=([^'"].*)$/
|
||||
match = line.match(re)
|
||||
if match
|
||||
# Quote the VIRTUAL_ENV var assignment to help virtualenv-tools work?
|
||||
patched << "VIRTUAL_ENV='#{match}'\n"
|
||||
else
|
||||
patched << line
|
||||
end
|
||||
end
|
||||
fd.close
|
||||
File.write(activate_bin, patched.join)
|
||||
|
||||
# Rewrite the base path inside the virtualenv to prepare it to be packaged.
|
||||
::Dir.chdir(virtualenv_build_folder) do
|
||||
safesystem("virtualenv-tools", "--update-path", virtualenv_folder)
|
||||
end
|
||||
|
|
@ -191,7 +216,6 @@ class FPM::Package::Virtualenv < FPM::Package
|
|||
dir.input(".")
|
||||
@staging_path = dir.staging_path
|
||||
dir.cleanup_build
|
||||
|
||||
end # def input
|
||||
|
||||
# Delete python precompiled files found in a given folder.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,39 @@
|
|||
require "fpm/namespace"
|
||||
require "ostruct"
|
||||
require "rake"
|
||||
require "rake/tasklib"
|
||||
|
||||
class FPM::RakeTask < Rake::TaskLib
|
||||
class Options
|
||||
attr_accessor :args
|
||||
|
||||
def initialize(defaults=nil)
|
||||
if defaults.nil?
|
||||
@h = Hash.new
|
||||
else
|
||||
@h = defaults
|
||||
end
|
||||
end
|
||||
|
||||
def method_missing(m, *args)
|
||||
if m.end_with?("=")
|
||||
raise ArgumentError, "#{self.class.name}##{m} ... Expected 1 arg, got #{args.length}" if args.length != 1
|
||||
@h[m[0...-1]] = args[0]
|
||||
else
|
||||
raise ArgumentError, "Expected 0 arg, got #{args.length}" if args.length != 0
|
||||
return @h[m]
|
||||
end
|
||||
end
|
||||
|
||||
def to_h
|
||||
return @h
|
||||
end
|
||||
end # Options
|
||||
|
||||
attr_reader :options
|
||||
|
||||
def initialize(package_name, opts = {}, &block)
|
||||
@options = OpenStruct.new(:name => package_name.to_s)
|
||||
#@options = OpenStruct.new(:name => package_name.to_s)
|
||||
@options = Options.new(:name => package_name.to_s)
|
||||
@source, @target = opts.values_at(:source, :target).map(&:to_s)
|
||||
@directory = File.expand_path(opts[:directory].to_s)
|
||||
|
||||
|
|
@ -18,8 +44,8 @@ class FPM::RakeTask < Rake::TaskLib
|
|||
|
||||
task(options.name) do |_, task_args|
|
||||
block.call(*[options, task_args].first(block.arity)) if block_given?
|
||||
abort("Must specify args") unless options.respond_to?(:args)
|
||||
@args = options.delete_field(:args)
|
||||
abort("Must specify args") if options.args.nil?
|
||||
@args = options.args
|
||||
run_cli
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
require "fpm/namespace"
|
||||
require "fileutils"
|
||||
require "stud/temporary"
|
||||
|
||||
# Some utility functions
|
||||
module FPM::Util
|
||||
|
|
@ -135,7 +136,7 @@ module FPM::Util
|
|||
raise ExecutableNotFound.new(program)
|
||||
end
|
||||
|
||||
logger.debug("Running command", :args => args2)
|
||||
logger.info("Running command", :args => args2)
|
||||
|
||||
stdout_r, stdout_w = IO.pipe
|
||||
stderr_r, stderr_w = IO.pipe
|
||||
|
|
@ -229,15 +230,18 @@ module FPM::Util
|
|||
@@ar_cmd_deterministic = false
|
||||
|
||||
# FIXME: don't assume current directory writeable
|
||||
FileUtils.touch(["fpm-dummy.tmp"])
|
||||
emptyfile = Stud::Temporary.pathname
|
||||
testarchive = Stud::Temporary.pathname
|
||||
FileUtils.touch([emptyfile])
|
||||
|
||||
["ar", "gar"].each do |ar|
|
||||
["-qc", "-qcD"].each do |ar_create_opts|
|
||||
FileUtils.rm_f(["fpm-dummy.ar.tmp"])
|
||||
FileUtils.rm_f([testarchive])
|
||||
# Return this combination if it creates archives without uids or timestamps.
|
||||
# Exitstatus will be nonzero if the archive can't be created,
|
||||
# or its table of contents doesn't match the regular expression.
|
||||
# Be extra-careful about locale and timezone when matching output.
|
||||
system("#{ar} #{ar_create_opts} fpm-dummy.ar.tmp fpm-dummy.tmp 2>/dev/null && env TZ=UTC LANG=C LC_TIME=C #{ar} -tv fpm-dummy.ar.tmp | grep '0/0.*1970' > /dev/null 2>&1")
|
||||
system("#{ar} #{ar_create_opts} #{testarchive} #{emptyfile} 2>/dev/null && env TZ=UTC LANG=C LC_TIME=C #{ar} -tv #{testarchive} | grep '0/0.*1970' > /dev/null 2>&1")
|
||||
if $?.exitstatus == 0
|
||||
@@ar_cmd = [ar, ar_create_opts]
|
||||
@@ar_cmd_deterministic = true
|
||||
|
|
@ -247,10 +251,8 @@ module FPM::Util
|
|||
end
|
||||
# If no combination of ar and options omits timestamps, fall back to default.
|
||||
@@ar_cmd = ["ar", "-qc"]
|
||||
FileUtils.rm_f([testarchive, emptyfile])
|
||||
return @@ar_cmd
|
||||
ensure
|
||||
# Clean up
|
||||
FileUtils.rm_f(["fpm-dummy.ar.tmp", "fpm-dummy.tmp"])
|
||||
end # def ar_cmd
|
||||
|
||||
# Return whether the command returned by ar_cmd can create deterministic archives
|
||||
|
|
@ -264,7 +266,10 @@ module FPM::Util
|
|||
return @@tar_cmd if defined? @@tar_cmd
|
||||
|
||||
# FIXME: don't assume current directory writeable
|
||||
FileUtils.touch(["fpm-dummy.tmp"])
|
||||
emptyfile = Stud::Temporary.pathname
|
||||
testarchive = Stud::Temporary.pathname
|
||||
|
||||
FileUtils.touch([emptyfile])
|
||||
|
||||
# Prefer tar that supports more of the features we want, stop if we find tar of our dreams
|
||||
best="tar"
|
||||
|
|
@ -276,7 +281,7 @@ module FPM::Util
|
|||
opts=[]
|
||||
score=0
|
||||
["--sort=name", "--mtime=@0"].each do |opt|
|
||||
system("#{tar} #{opt} -cf fpm-dummy.tar.tmp fpm-dummy.tmp > /dev/null 2>&1")
|
||||
system("#{tar} #{opt} -cf #{testarchive} #{emptyfile} > /dev/null 2>&1")
|
||||
if $?.exitstatus == 0
|
||||
opts << opt
|
||||
score += 1
|
||||
|
|
@ -292,10 +297,9 @@ module FPM::Util
|
|||
end
|
||||
end
|
||||
@@tar_cmd = best
|
||||
FileUtils.rm_f([testarchive, emptyfile])
|
||||
|
||||
return @@tar_cmd
|
||||
ensure
|
||||
# Clean up
|
||||
FileUtils.rm_f(["fpm-dummy.tar.tmp", "fpm-dummy.tmp"])
|
||||
end # def tar_cmd
|
||||
|
||||
# Return whether the command returned by tar_cmd can create deterministic archives
|
||||
|
|
@ -328,7 +332,15 @@ module FPM::Util
|
|||
|
||||
|
||||
def copy_entry(src, dst, preserve=false, remove_destination=false)
|
||||
case File.ftype(src)
|
||||
st = File.lstat(src)
|
||||
|
||||
filetype = if st.ftype == "file" && st.nlink > 1
|
||||
"hardlink"
|
||||
else
|
||||
st.ftype
|
||||
end
|
||||
|
||||
case filetype
|
||||
when 'fifo'
|
||||
if File.respond_to?(:mkfifo)
|
||||
File.mkfifo(dst)
|
||||
|
|
@ -346,18 +358,23 @@ module FPM::Util
|
|||
raise UnsupportedSpecialFile.new("File is device which fpm doesn't know how to copy (#{File.ftype(src)}): #{src}")
|
||||
when 'directory'
|
||||
FileUtils.mkdir(dst) unless File.exist? dst
|
||||
else
|
||||
# if the file with the same dev and inode has been copied already -
|
||||
when 'hardlink'
|
||||
# Handle hardlinks
|
||||
# if the file with the same dev and inode has been copied already.
|
||||
# hard link it's copy to `dst`, otherwise make an actual copy
|
||||
st = File.lstat(src)
|
||||
known_entry = copied_entries[[st.dev, st.ino]]
|
||||
if known_entry
|
||||
FileUtils.ln(known_entry, dst)
|
||||
logger.debug("Copying hardlink", :src => src, :dst => dst, :link => known_entry)
|
||||
else
|
||||
FileUtils.copy_entry(src, dst, preserve, false,
|
||||
remove_destination)
|
||||
copied_entries[[st.dev, st.ino]] = dst
|
||||
end
|
||||
else
|
||||
# Normal file, just copy it.
|
||||
FileUtils.copy_entry(src, dst, preserve, false,
|
||||
remove_destination)
|
||||
end # else...
|
||||
end # def copy_entry
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
module FPM
|
||||
VERSION = "1.15.1"
|
||||
VERSION = "1.17.0"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,72 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ ! -f "mk/bsd.pkg.mk" ] ; then
|
||||
# TODO(sissel): Maybe download pkgsrc ourselves.
|
||||
echo "Current directory doesn't appear to be a pkgsrc tree. ($PWD)"
|
||||
echo "I was expecting to find file: ./mk/bsd.pkg.mk"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "build/usr/local/bin/bmake" ] ; then
|
||||
# TODO(sissel): Maybe bootstrap ourselves.
|
||||
echo "This script requires pkgsrc to be bootstrapped in a specific way."
|
||||
echo "I expected to find file: build/usr/local/bin/bmake and did not"
|
||||
echo
|
||||
echo "Bootstrap with:"
|
||||
echo "SH=/bin/bash ./bootstrap/bootstrap --unprivileged --prefix $PWD/build/usr/local --pkgdbdir $PWD/pkgdb"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# TODO(sissel): put some flags.
|
||||
|
||||
LOCALBASE="/usr/local"
|
||||
DESTDIR=$PWD/build
|
||||
|
||||
mkdir -p "$DESTDIR"
|
||||
|
||||
export PATH=$DESTDIR/$LOCALBASE/bin:$DESTDIR/$LOCALBASE/sbin:$PATH
|
||||
|
||||
for i in "$@" ; do
|
||||
# process dependencies first before the final target.
|
||||
set -- $(bmake -C "$@" show-depends-pkgpaths) "$@"
|
||||
done
|
||||
|
||||
TARGETS="$*"
|
||||
|
||||
for target in $TARGETS; do
|
||||
set --
|
||||
|
||||
eval "$(bmake -C $target show-vars-eval VARS="PKGNAME PKGVERSION")"
|
||||
name="$(echo "$PKGNAME" | sed -e "s/-$PKGVERSION\$//")"
|
||||
orig_version=${PKGVERSION}
|
||||
version=${PKGVERSION}-pkgsrc
|
||||
|
||||
# Purge old package
|
||||
rm packages/All/$PKGNAME.tgz
|
||||
|
||||
pkg_delete $name > /dev/null 2>&1
|
||||
|
||||
bmake -C $target clean || exit 1
|
||||
bmake -C $target USE_DESTDIR=yes LOCALBASE=$LOCALBASE PREFIX=$LOCALBASE \
|
||||
DESTDIR=$DESTDIR SKIP_DEPENDS=yes \
|
||||
clean package || exit 1
|
||||
|
||||
# Start building fpm args
|
||||
set -- -n "$name" -v "$version" --prefix $LOCALBASE
|
||||
|
||||
# Skip the pkgsrc package metadata files
|
||||
set -- "$@" --exclude '+*'
|
||||
|
||||
# Handle deps
|
||||
for dep in $(bmake -C $target show-depends-pkgpaths) ; do
|
||||
eval "$(bmake -C $dep show-vars-eval VARS="PKGNAME PKGVERSION")"
|
||||
PKGNAME="$(echo "$PKGNAME" | sed -e "s/-$PKGVERSION\$//")"
|
||||
set -- "$@" -d "$PKGNAME (= $PKGVERSION-pkgsrc)"
|
||||
done
|
||||
|
||||
set -- -s tar -t deb "$@"
|
||||
set -- "$@" packages/All/$name-$orig_version.tgz
|
||||
fpm "$@"
|
||||
done
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[project]
|
||||
name = "example"
|
||||
version = "1.2.3"
|
||||
authors = [ { name = "Captain Fancy", email = "foo@example.com" } ]
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
Metadata-Version: 2.4
|
||||
Name: Django
|
||||
Version: 5.2.6
|
||||
Summary: A high-level Python web framework that encourages rapid development and clean, pragmatic design.
|
||||
Author-email: Django Software Foundation <foundation@djangoproject.com>
|
||||
License: BSD-3-Clause
|
||||
Project-URL: Homepage, https://www.djangoproject.com/
|
||||
Project-URL: Documentation, https://docs.djangoproject.com/
|
||||
Project-URL: Release notes, https://docs.djangoproject.com/en/stable/releases/
|
||||
Project-URL: Funding, https://www.djangoproject.com/fundraising/
|
||||
Project-URL: Source, https://github.com/django/django
|
||||
Project-URL: Tracker, https://code.djangoproject.com/
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Web Environment
|
||||
Classifier: Framework :: Django
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Topic :: Internet :: WWW/HTTP
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
||||
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
|
||||
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Requires-Python: >=3.10
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
License-File: LICENSE.python
|
||||
License-File: AUTHORS
|
||||
Requires-Dist: asgiref>=3.8.1
|
||||
Requires-Dist: sqlparse>=0.3.1
|
||||
Requires-Dist: tzdata; sys_platform == "win32"
|
||||
Provides-Extra: argon2
|
||||
Requires-Dist: argon2-cffi>=19.1.0; extra == "argon2"
|
||||
Provides-Extra: bcrypt
|
||||
Requires-Dist: bcrypt; extra == "bcrypt"
|
||||
Dynamic: license-file
|
||||
|
||||
======
|
||||
Django
|
||||
======
|
||||
|
||||
Django is a high-level Python web framework that encourages rapid development
|
||||
and clean, pragmatic design. Thanks for checking it out.
|
||||
|
||||
All documentation is in the "``docs``" directory and online at
|
||||
https://docs.djangoproject.com/en/stable/. If you're just getting started,
|
||||
here's how we recommend you read the docs:
|
||||
|
||||
* First, read ``docs/intro/install.txt`` for instructions on installing Django.
|
||||
|
||||
* Next, work through the tutorials in order (``docs/intro/tutorial01.txt``,
|
||||
``docs/intro/tutorial02.txt``, etc.).
|
||||
|
||||
* If you want to set up an actual deployment server, read
|
||||
``docs/howto/deployment/index.txt`` for instructions.
|
||||
|
||||
* You'll probably want to read through the topical guides (in ``docs/topics``)
|
||||
next; from there you can jump to the HOWTOs (in ``docs/howto``) for specific
|
||||
problems, and check out the reference (``docs/ref``) for gory details.
|
||||
|
||||
* See ``docs/README`` for instructions on building an HTML version of the docs.
|
||||
|
||||
Docs are updated rigorously. If you find any problems in the docs, or think
|
||||
they should be clarified in any way, please take 30 seconds to fill out a
|
||||
ticket here: https://code.djangoproject.com/newticket
|
||||
|
||||
To get more help:
|
||||
|
||||
* Join the ``#django`` channel on ``irc.libera.chat``. Lots of helpful people
|
||||
hang out there. `Webchat is available <https://web.libera.chat/#django>`_.
|
||||
|
||||
* Join the `Django Discord community <https://chat.djangoproject.com>`_.
|
||||
|
||||
* Join the community on the `Django Forum <https://forum.djangoproject.com/>`_.
|
||||
|
||||
To contribute to Django:
|
||||
|
||||
* Check out https://docs.djangoproject.com/en/dev/internals/contributing/ for
|
||||
information about getting involved.
|
||||
|
||||
To run Django's test suite:
|
||||
|
||||
* Follow the instructions in the "Unit tests" section of
|
||||
``docs/internals/contributing/writing-code/unit-tests.txt``, published online at
|
||||
https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/unit-tests/#running-the-unit-tests
|
||||
|
||||
Supporting the Development of Django
|
||||
====================================
|
||||
|
||||
Django's development depends on your contributions.
|
||||
|
||||
If you depend on Django, remember to support the Django Software Foundation: https://www.djangoproject.com/fundraising/
|
||||
|
|
@ -10,9 +10,6 @@ setup(name="Example",
|
|||
package_dir={},
|
||||
install_requires=[
|
||||
"Dependency1", "dependency2",
|
||||
# XXX: I don't know what these python_version-dependent deps mean
|
||||
# needs investigation
|
||||
# Reference: PEP-0508
|
||||
'rtxt-dep3; python_version == "2.0"',
|
||||
'rtxt-dep4; python_version > "2.0"',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -53,7 +53,13 @@ describe FPM::Package::Deb do
|
|||
|
||||
it "should default to native" do
|
||||
# Convert kernel name to debian name
|
||||
expected = native == "x86_64" ? "amd64" : native
|
||||
expected = if native == "x86_64"
|
||||
"amd64"
|
||||
elsif native == "aarch64"
|
||||
"arm64"
|
||||
else
|
||||
native
|
||||
end
|
||||
expect(subject.architecture).to(be == expected)
|
||||
end
|
||||
end
|
||||
|
|
@ -407,7 +413,7 @@ describe FPM::Package::Deb do
|
|||
|
||||
context "when run against lintian" do
|
||||
before do
|
||||
skip("Missing lintian program") unless have_lintian
|
||||
skip("Missing lintian program") unless have_lintian
|
||||
end
|
||||
|
||||
lintian_errors_to_ignore = [
|
||||
|
|
@ -529,7 +535,8 @@ describe FPM::Package::Deb do
|
|||
{
|
||||
"bzip2" => "bz2",
|
||||
"xz" => "xz",
|
||||
"gz" => "gz"
|
||||
"gz" => "gz",
|
||||
"zst" => "zst"
|
||||
}.each do |flag,suffix|
|
||||
context "when --deb-compression is #{flag}" do
|
||||
let(:target) { Stud::Temporary.pathname + ".deb" }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ require "spec_setup"
|
|||
require "fpm" # local
|
||||
require "fpm/package/dir" # local
|
||||
require "stud/temporary"
|
||||
require "insist/assert"
|
||||
|
||||
if RUBY_VERSION =~ /^1\.8/
|
||||
# The following method copied from ruby 1.9.3
|
||||
|
|
@ -126,6 +127,49 @@ describe FPM::Package::Dir do
|
|||
subject.output(output)
|
||||
insist { File }.exist?(File.join(output, "foo", "a", "a=b"))
|
||||
end
|
||||
|
||||
it "should create two normal files when one normal file is copied to two different locations" do
|
||||
# For issue #2102
|
||||
# With the following: fpm -s dir ... pathA=/location1 pathA=location2
|
||||
# The above command was copying pathA to both locations but hardlinking them instead of creating normal files.
|
||||
|
||||
foo = File.join(tmpdir, "foo")
|
||||
File.write(foo, "hello world")
|
||||
|
||||
paths = [ "/opt/example/foo", "/usr/share/example/foo" ]
|
||||
paths.each do |path|
|
||||
subject.input("#{foo}=#{path}")
|
||||
end
|
||||
|
||||
subject.output(output)
|
||||
|
||||
outfiles = paths.collect { |path| File.join(output, path) }
|
||||
|
||||
expect(outfiles).to all(satisfy("have link count == 1") { |path| File.lstat(path).nlink == 1 })
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "hardlinks" do
|
||||
it "should create hardlinks when inputs are hardlinks (within the context of the target package)" do
|
||||
# For issue #2102
|
||||
# With the following: fpm -s dir ... pathA=/location1 pathA=location2
|
||||
# The above command was copying pathA to both locations but hardlinking them instead of creating normal files.
|
||||
|
||||
foo = File.join(tmpdir, "foo")
|
||||
bar = File.join(tmpdir, "bar")
|
||||
File.write(foo, "hello world")
|
||||
File.link(foo, bar)
|
||||
|
||||
subject.attributes[:chdir] = tmpdir
|
||||
subject.input(".")
|
||||
|
||||
subject.output(output)
|
||||
|
||||
outfiles = ["foo", "bar"].collect { |path| File.join(output, path) }
|
||||
|
||||
expect(outfiles).to all(satisfy("have link count == 2") { |path| File.stat(path).nlink == 2 })
|
||||
end
|
||||
end
|
||||
|
||||
context "SYMLINKS." do
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ end
|
|||
describe FPM::Package::Python do
|
||||
before do
|
||||
skip("Python program not found") unless python_usable?
|
||||
subject.attributes[:python_bin] = find_python
|
||||
#subject.attributes[:python_bin] = find_python
|
||||
end
|
||||
|
||||
let (:example_dir) do
|
||||
|
|
@ -50,16 +50,15 @@ describe FPM::Package::Python do
|
|||
before :each do
|
||||
subject.attributes[:python_downcase_name?] = false
|
||||
end
|
||||
|
||||
context "when :python_fix_name? is true" do
|
||||
before :each do
|
||||
subject.attributes[:python_fix_name?] = true
|
||||
end
|
||||
|
||||
context "and :python_package_name_prefix is nil/default" do
|
||||
it "should prefix the package with 'python-'" do
|
||||
it "should prefix the package name based on detected python-bin name" do
|
||||
subject.input(example_dir)
|
||||
insist { subject.name } == "python-Example"
|
||||
insist { subject.name } == "#{subject.attributes[:python_bin]}-Example"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -67,6 +66,7 @@ describe FPM::Package::Python do
|
|||
it "should prefix the package name appropriately" do
|
||||
prefix = "whoa"
|
||||
subject.attributes[:python_package_name_prefix] = prefix
|
||||
subject.attributes[:python_package_name_prefix_given?] = true
|
||||
subject.input(example_dir)
|
||||
insist { subject.name } == "#{prefix}-Example"
|
||||
end
|
||||
|
|
@ -96,9 +96,10 @@ describe FPM::Package::Python do
|
|||
end
|
||||
|
||||
context "and :python_package_name_prefix is nil/default" do
|
||||
it "should prefix the package with 'python-'" do
|
||||
it "should prefix the package based on the version of python" do
|
||||
subject.input(example_dir)
|
||||
insist { subject.name } == "python-example"
|
||||
insist { subject.attributes[:python_package_name_prefix_given?] }.nil?
|
||||
insist { subject.name } == "#{subject.attributes[:python_bin]}-example"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -106,6 +107,7 @@ describe FPM::Package::Python do
|
|||
it "should prefix the package name appropriately" do
|
||||
prefix = "whoa"
|
||||
subject.attributes[:python_package_name_prefix] = prefix
|
||||
subject.attributes[:python_package_name_prefix_given?] = true
|
||||
subject.input(example_dir)
|
||||
insist { subject.name } == "#{prefix}-example"
|
||||
end
|
||||
|
|
@ -130,9 +132,24 @@ describe FPM::Package::Python do
|
|||
end
|
||||
|
||||
it "it should include the dependencies from setup.py" do
|
||||
# Insist on using the defaults for this test, prefix not given and
|
||||
# prefix should automatically be based on the python major version
|
||||
insist { subject.attributes[:python_package_name_prefix_given?] }.nil?
|
||||
subject.input(example_dir)
|
||||
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
|
||||
# The package name prefix attribute should be set to _something_ by default
|
||||
reject { prefix }.nil?
|
||||
|
||||
# XXX: Why is there extra whitespace in these strings?
|
||||
insist { subject.dependencies.sort } == ["python-dependency1 ","python-dependency2 ", "python-rtxt-dep4 "]
|
||||
#
|
||||
# Note: The dependency list should only include entries which are supported by fpm.
|
||||
# python dependencies can have 'environment markers' and most of those markers are
|
||||
# not supported by fpm.
|
||||
# In this test, there are (at time of writing) some python_version markers and fpm doesn't
|
||||
# support those.
|
||||
insist { subject.dependencies.sort } == ["#{prefix}-dependency1","#{prefix}-dependency2", "#{prefix}-rtxt-dep4"]
|
||||
end
|
||||
|
||||
context "and :python_disable_dependency is set" do
|
||||
|
|
@ -142,7 +159,8 @@ describe FPM::Package::Python do
|
|||
|
||||
it "it should exclude the dependency" do
|
||||
subject.input(example_dir)
|
||||
insist { subject.dependencies.sort } == ["python-dependency2 ", "python-rtxt-dep4 "]
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
insist { subject.dependencies.sort } == ["#{prefix}-dependency2", "#{prefix}-rtxt-dep4"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -160,13 +178,15 @@ describe FPM::Package::Python do
|
|||
|
||||
it "it should prefix requirements.txt" do
|
||||
subject.input(example_dir)
|
||||
insist { subject.dependencies.sort } == ["python-rtxt-dep1 > 0.1", "python-rtxt-dep2 = 0.1", "python-rtxt-dep4 "]
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
insist { subject.dependencies.sort } == ["#{prefix}-rtxt-dep1 > 0.1", "#{prefix}-rtxt-dep2 = 0.1", "#{prefix}-rtxt-dep4"]
|
||||
end
|
||||
|
||||
it "it should exclude the dependency" do
|
||||
subject.attributes[:python_disable_dependency] = "rtxt-dep1"
|
||||
subject.input(example_dir)
|
||||
insist { subject.dependencies.sort } == ["python-rtxt-dep2 = 0.1", "python-rtxt-dep4 "]
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
insist { subject.dependencies.sort } == ["#{prefix}-rtxt-dep2 = 0.1", "#{prefix}-rtxt-dep4"]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -177,41 +197,120 @@ describe FPM::Package::Python do
|
|||
|
||||
it "it should load requirements.txt" do
|
||||
subject.input(example_dir)
|
||||
insist { subject.dependencies.sort } == ["rtxt-dep1 > 0.1", "rtxt-dep2 = 0.1", "rtxt-dep4 "]
|
||||
insist { subject.dependencies.sort } == ["rtxt-dep1 > 0.1", "rtxt-dep2 = 0.1", "rtxt-dep4"]
|
||||
end
|
||||
|
||||
it "it should exclude the dependency" do
|
||||
subject.attributes[:python_disable_dependency] = "rtxt-dep1"
|
||||
subject.input(example_dir)
|
||||
insist { subject.dependencies.sort } == ["rtxt-dep2 = 0.1", "rtxt-dep4 "]
|
||||
insist { subject.dependencies.sort } == ["rtxt-dep2 = 0.1", "rtxt-dep4"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "python_scripts_executable is set" do
|
||||
it "should have scripts with a custom hashbang line" do
|
||||
pending("Disabled on travis-ci becaulamese it always fails, and there is no way to debug it?") if is_travis
|
||||
skip("Requires python3 executable") unless program_exists?("python3")
|
||||
context "when input is a name" do
|
||||
it "should download from pypi" do
|
||||
subject.input("click==8.3.0")
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
|
||||
subject.attributes[:python_scripts_executable] = "fancypants"
|
||||
# Newer versions of Django require Python 3.
|
||||
subject.attributes[:python_bin] = "python3"
|
||||
subject.input("django")
|
||||
insist { subject.name } == "#{prefix}-click"
|
||||
insist { subject.version } == "8.3.0"
|
||||
insist { subject.maintainer } == "Pallets <contact@palletsprojects.com>"
|
||||
insist { subject.architecture } == "all"
|
||||
insist { subject.dependencies } == [ ]
|
||||
|
||||
# Determine, where 'easy_install' is going to install scripts
|
||||
#script_dir = easy_install_default(subject.attributes[:python_bin], 'script_dir')
|
||||
#path = subject.staging_path(File.join(script_dir, "django-admin.py"))
|
||||
|
||||
# Hardcode /usr/local/bin here. On newer Python 3's I cannot figure out how to
|
||||
# determine the script_dir at installation time. easy_install's method is gone.
|
||||
path = subject.staging_path("/usr/local/bin/django-admin")
|
||||
|
||||
# Read the first line (the hashbang line) of the django-admin.py script
|
||||
fd = File.new(path, "r")
|
||||
topline = fd.readline
|
||||
fd.close
|
||||
|
||||
insist { topline.chomp } == "#!fancypants"
|
||||
end
|
||||
end
|
||||
|
||||
context "when given a project containing a pyproject.toml" do
|
||||
let (:project) do
|
||||
File.expand_path("../../fixtures/python-pyproject.toml/", File.dirname(__FILE__))
|
||||
end
|
||||
|
||||
it "should package it correctly" do
|
||||
subject.input(project)
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
|
||||
insist { subject.name } == "#{prefix}-example"
|
||||
insist { subject.version } == "1.2.3"
|
||||
insist { subject.maintainer } == "Captain Fancy <foo@example.com>"
|
||||
end
|
||||
|
||||
it "should package it correctly even if the path given is directly to the pyproject.toml" do
|
||||
subject.input(File.join(project, "pyproject.toml"))
|
||||
prefix = subject.attributes[:python_package_name_prefix]
|
||||
|
||||
insist { subject.name } == "#{prefix}-example"
|
||||
insist { subject.version } == "1.2.3"
|
||||
insist { subject.maintainer } == "Captain Fancy <foo@example.com>"
|
||||
end
|
||||
|
||||
end
|
||||
end # describe FPM::Package::Python
|
||||
|
||||
describe FPM::Package::Python::PythonMetadata do
|
||||
|
||||
context "processing simple examples" do
|
||||
let(:text) {
|
||||
[
|
||||
"Metadata-Version: 2.4",
|
||||
"Name: hello",
|
||||
"Version: 1.0",
|
||||
].join("\n") + "\n"
|
||||
}
|
||||
subject { described_class.from(text) }
|
||||
|
||||
it "should" do
|
||||
insist { subject.name } == "hello"
|
||||
insist { subject.version } == "1.0"
|
||||
end
|
||||
end
|
||||
|
||||
# Use a known METADATA file from a real Python package
|
||||
context "when parsing Django 5.2.6's METADATA" do
|
||||
let(:text) do
|
||||
File.read(File.expand_path("../../fixtures/python/METADATA", File.dirname(__FILE__)))
|
||||
end
|
||||
|
||||
expectations = {
|
||||
"Metadata-Version" => "2.4",
|
||||
"Name" => "Django",
|
||||
"Version" => "5.2.6",
|
||||
"Summary" => "A high-level Python web framework that encourages rapid development and clean, pragmatic design.",
|
||||
"Author-email" => "Django Software Foundation <foundation@djangoproject.com>",
|
||||
"License" => "BSD-3-Clause",
|
||||
}
|
||||
|
||||
let(:parsed) { described_class.parse(text) }
|
||||
let(:headers) { parsed[0] }
|
||||
let(:body) { parsed[1] }
|
||||
|
||||
let(:metadata) { described_class.from(text) }
|
||||
|
||||
expectations.each do |field, value|
|
||||
it "the #{field} field should be #{value.inspect}" do
|
||||
insist { headers[field] } == value
|
||||
end
|
||||
end
|
||||
|
||||
it "should parse multivalue fields into an array value" do
|
||||
insist { headers["Classifier"] }.is_a?(Enumerable)
|
||||
insist { headers["Project-URL"] }.is_a?(Enumerable)
|
||||
insist { headers["Requires-Dist"] }.is_a?(Enumerable)
|
||||
|
||||
insist { headers["Requires-Dist"] }.include?('asgiref>=3.8.1')
|
||||
insist { headers["Requires-Dist"] }.include?('sqlparse>=0.3.1')
|
||||
insist { headers["Requires-Dist"] }.include?('tzdata; sys_platform == "win32"')
|
||||
insist { headers["Requires-Dist"] }.include?('argon2-cffi>=19.1.0; extra == "argon2"')
|
||||
insist { headers["Requires-Dist"] }.include?('bcrypt; extra == "bcrypt"')
|
||||
end
|
||||
|
||||
it "should provide correctly parsed values" do
|
||||
insist { metadata.name } == "Django"
|
||||
insist { metadata.version } == "5.2.6"
|
||||
insist { metadata.summary } == "A high-level Python web framework that encourages rapid development and clean, pragmatic design."
|
||||
insist { metadata.license } == "BSD-3-Clause"
|
||||
insist { metadata.homepage } == "https://www.djangoproject.com/"
|
||||
end
|
||||
end # parsing Django METADATA
|
||||
end
|
||||
|
|
|
|||
|
|
@ -484,6 +484,45 @@ describe FPM::Package::RPM do
|
|||
File.unlink(@target)
|
||||
end
|
||||
end # dist
|
||||
|
||||
context "changelog" do
|
||||
it "should generate a changelog in the release" do
|
||||
subject.name = "example"
|
||||
subject.attributes[:rpm_dist] = 'rhel'
|
||||
subject.version = "1.2.3"
|
||||
subject.maintainer = "Spec Test <spec.test@example.com>"
|
||||
@target = Stud::Temporary.pathname
|
||||
|
||||
# Write RPM
|
||||
subject.output(@target)
|
||||
|
||||
@rpm = ::RPM::File.new(@target)
|
||||
insist { @rpm.tags[:changelogname] } == [ "Spec Test <spec.test@example.com> - 1.2.3-1.rhel" ]
|
||||
insist { @rpm.tags[:changelogtext] } == [ "- Package created with FPM" ]
|
||||
|
||||
File.unlink(@target)
|
||||
end
|
||||
|
||||
it "should have the changelog in the release" do
|
||||
subject.name = "example"
|
||||
subject.attributes[:rpm_changelog] = <<CHANGELOG
|
||||
* Tue May 31 2016 Example Maintainers <fpm@example.com> - 1.0-1
|
||||
- First example package
|
||||
CHANGELOG
|
||||
subject.version = "1.0"
|
||||
@target = Stud::Temporary.pathname
|
||||
|
||||
# Write RPM
|
||||
subject.output(@target)
|
||||
|
||||
@rpm = ::RPM::File.new(@target)
|
||||
insist { @rpm.tags[:changelogtime] } == [ 1464696000 ]
|
||||
insist { @rpm.tags[:changelogname] } == [ "Example Maintainers <fpm@example.com> - 1.0-1" ]
|
||||
insist { @rpm.tags[:changelogtext] } == [ "- First example package" ]
|
||||
|
||||
File.unlink(@target)
|
||||
end
|
||||
end # changelog
|
||||
end # #output
|
||||
|
||||
describe "prefix attribute" do
|
||||
|
|
@ -530,6 +569,15 @@ describe FPM::Package::RPM do
|
|||
insist { rpm.files } == [ "/example/%name%" ]
|
||||
end
|
||||
|
||||
it "should escape '{' and '}' characters in filenames" do
|
||||
Dir.mkdir(subject.staging_path("/example"))
|
||||
File.write(subject.staging_path("/example/{{ test }}"), "Hello")
|
||||
subject.output(@target)
|
||||
|
||||
rpm = ::RPM::File.new(@target)
|
||||
insist { rpm.files } == [ "/example/{{ test }}" ]
|
||||
end
|
||||
|
||||
it "should correctly include files with spaces and quotation marks" do
|
||||
names = [
|
||||
"/It's time to go.txt",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ $: << File.join(File.dirname(File.dirname(__FILE__)), "lib")
|
|||
require "fpm/util"
|
||||
include FPM::Util
|
||||
|
||||
Cabin::Channel.get.level = :error
|
||||
spec_logger = Cabin::Channel.get("rspec")
|
||||
spec_logger.subscribe(STDOUT)
|
||||
spec_logger.level = :error
|
||||
|
||||
# Enable debug logs if requested.
|
||||
if $DEBUG or ENV["DEBUG"]
|
||||
Cabin::Channel.get.level = :debug
|
||||
|
|
@ -28,10 +33,6 @@ else
|
|||
end
|
||||
end
|
||||
|
||||
Cabin::Channel.get.level = :error
|
||||
spec_logger = Cabin::Channel.get("rspec")
|
||||
spec_logger.subscribe(STDOUT)
|
||||
spec_logger.level = :error
|
||||
|
||||
# Quiet the output of all system() calls
|
||||
module Kernel
|
||||
|
|
|
|||
|
|
@ -260,4 +260,4 @@ fi
|
|||
<% end -%>
|
||||
|
||||
%changelog
|
||||
<%= attributes[:rpm_changelog] %>
|
||||
<%= changelog %>
|
||||
|
|
|
|||
Loading…
Reference in New Issue