Compare commits
4 Commits
main
...
pull/1681-
| Author | SHA1 | Date |
|---|---|---|
|
|
d590cc3e18 | |
|
|
d4746c105a | |
|
|
958e82ffed | |
|
|
16ba27251e |
|
|
@ -42,3 +42,6 @@ Gemfile.lock
|
|||
|
||||
docs/_build
|
||||
docs/.work
|
||||
|
||||
.docker-test-everything
|
||||
.docker-test-minimal
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ sbuss
|
|||
Brett Gailey (github: dnbert)
|
||||
Daniel Haskin (github: djhaskin987)
|
||||
Richard Grainger (github: liger1978)
|
||||
seph (github: directionless)
|
||||
|
||||
If you have contributed (bug reports, feature requests, help in IRC, blog
|
||||
posts, code, etc) and aren't listed here, please let me know if you wish to be
|
||||
|
|
|
|||
109
Dockerfile
109
Dockerfile
|
|
@ -1,17 +1,94 @@
|
|||
#
|
||||
# To build this Docker image: docker build -t fpm .
|
||||
#
|
||||
# To run this Docker container interactively: docker run -it fpm
|
||||
#
|
||||
FROM alpine:3.12
|
||||
# Are we running against the minimal container, or the everything
|
||||
# container? Minimal is mostly the compiled package tools. Everything
|
||||
# pulls in scripting langauges.
|
||||
ARG BASE_ENV=everything
|
||||
|
||||
RUN apk add --no-cache \
|
||||
ruby \
|
||||
ruby-dev \
|
||||
ruby-etc \
|
||||
gcc \
|
||||
libffi-dev \
|
||||
make \
|
||||
libc-dev \
|
||||
rpm \
|
||||
&& gem install --no-document fpm
|
||||
# Are we running tests, or a release? Tests build and run against the
|
||||
# CWD, where release will use the downloaded gem.
|
||||
ARG TARGET=test
|
||||
|
||||
# Container to throw an error if called with a bare `docker build .`
|
||||
FROM ubuntu:18.04 as error
|
||||
RUN echo "\n\n\nHey! Use buildkit. See the Makefile or docs\n\n\n"
|
||||
RUN false
|
||||
|
||||
# Base container is used for various release and test things
|
||||
FROM ubuntu:18.04 as minimal-base
|
||||
|
||||
# Runtime deps. Build deps go in the build or test containers
|
||||
RUN apt-get update \
|
||||
&& apt-get -y dist-upgrade \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
ruby rubygems rubygems-integration \
|
||||
bsdtar \
|
||||
cpio \
|
||||
debsigs \
|
||||
pacman \
|
||||
rpm \
|
||||
squashfs-tools \
|
||||
xz-utils \
|
||||
zip \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
RUN adduser fpm
|
||||
|
||||
# everything container includes all the scripting languages. These
|
||||
# greatly embiggen the underlying docker container, so they're
|
||||
# conditionalized.
|
||||
FROM minimal-base AS everything-base
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
cpanminus \
|
||||
npm \
|
||||
perl \
|
||||
python3-pip \
|
||||
&& pip3 --no-cache-dir install setuptools \
|
||||
&& pip3 --no-cache-dir install wheel \
|
||||
&& pip3 --no-cache-dir install virtualenv virtualenv-tools3 \
|
||||
&& update-alternatives --install /usr/bin/python python /usr/bin/python3 10 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Run tests against the current working directory. This is a bit
|
||||
# orthogonal to the container release process, but it has a lot of
|
||||
# same dependancies, so we reuse it. This uses COPY to allow rspect to
|
||||
# initall the gems, but runtime usage expects you to mount a volume
|
||||
# into /src
|
||||
FROM ${BASE_ENV}-base AS test
|
||||
WORKDIR /src
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
gcc make ruby-dev libc-dev lintian git
|
||||
# installing ffi here is a bit of an optimization for how COPY and layer reuse works
|
||||
RUN gem install --no-ri --no-rdoc ffi
|
||||
|
||||
RUN install -d -o fpm /origsrc
|
||||
COPY --chown=fpm . /origsrc
|
||||
ENV HOME=/origsrc
|
||||
ENV BUNDLE_PATH=/origsrc/.bundle
|
||||
# Install a specific version of bundler
|
||||
WORKDIR /origsrc
|
||||
RUN gem install -v "$(grep -A1 '^BUNDLED WITH' Gemfile.lock | tail -1)" bundler
|
||||
USER fpm
|
||||
RUN bundle install
|
||||
CMD bundle exec rspec
|
||||
|
||||
# build a container from a released gem. install build deps here, so
|
||||
# we can omit them from the final release package
|
||||
FROM ${BASE_ENV}-base AS build
|
||||
RUN apt-get update
|
||||
RUN apt-get install --no-install-recommends -y \
|
||||
gcc make ruby-dev libc-dev
|
||||
ENV GEM_PATH /fpm
|
||||
ENV PATH "/fpm/bin:${PATH}"
|
||||
RUN gem install --no-ri --no-rdoc --install-dir=/fpm fpm
|
||||
|
||||
FROM build as release
|
||||
COPY --from=build /fpm /fpm
|
||||
ENV GEM_PATH /fpm
|
||||
ENV PATH "/fpm/bin:${PATH}"
|
||||
WORKDIR /src
|
||||
ENTRYPOINT ["/fpm/bin/fpm"]
|
||||
|
||||
# This target is to help docker buildkit in resolving things.
|
||||
FROM ${TARGET} as final
|
||||
|
|
|
|||
15
Makefile
15
Makefile
|
|
@ -52,3 +52,18 @@ clean:
|
|||
|
||||
publish-docs:
|
||||
$(MAKE) -C docs publish
|
||||
|
||||
# Testing in docker.
|
||||
# The dot file is a sentinal file that will built a docker image, and tag it.
|
||||
# The normal make target runs said image, mounting CWD against it.
|
||||
SECONDARY: .docker-test-minimal .docker-test-everything
|
||||
.docker-test-%: Gemfile.lock fpm.gemspec Dockerfile
|
||||
DOCKER_BUILDKIT=1 docker build -t fpm-test-$* --build-arg BASE_ENV=$* --build-arg TARGET=test .
|
||||
touch "$@"
|
||||
|
||||
docker-test-%: .docker-test-%
|
||||
docker run -v `pwd`:/src fpm-test-$*
|
||||
|
||||
docker-release-%:
|
||||
DOCKER_BUILDKIT=1 docker build -t fpm --build-arg BASE_ENV=$* --build-arg TARGET=release --squash .
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
FPM and Docker
|
||||
==============
|
||||
|
||||
Because fpm depends on so many underlying system tools, docker can
|
||||
alleviate the need to install them locally.
|
||||
|
||||
An end user may use a docker container in lieu of installing
|
||||
locally. And a developer can use docker to run the test suite.
|
||||
|
||||
|
||||
Running FPM inside docker
|
||||
-------------------------
|
||||
|
||||
First, build a container will all the dependencies::
|
||||
|
||||
make docker-release-everything
|
||||
|
||||
Now, run it as you would the fpm command. Note that you will have to
|
||||
mount your source directly into the docker volume::
|
||||
|
||||
docker run -v $(pwd):/src fpm --help
|
||||
|
||||
As a full example::
|
||||
|
||||
mkdir /tmp/fpm-test
|
||||
mkdir /tmp/fpm-test/files
|
||||
touch /tmp/fpm-test/files/one
|
||||
touch /tmp/fpm-test/files/two
|
||||
|
||||
docker run -v /tmp/fpm-test/files:/src -v /tmp/fpm-test:/out fpm -s dir -t tar -n example -p /out/out.tar .
|
||||
|
||||
tar tf /tmp/fpm-test/out.tar
|
||||
|
||||
Depending on your needs, you will have to adjust the volume mounts and
|
||||
relative paths to fit your particular situation.
|
||||
|
||||
Running rpsec inside docker
|
||||
---------------------------
|
||||
|
||||
The Makefile provides some targets for testing. They will build a
|
||||
docker container with the dependencies, and then invoked `rspec`
|
||||
inside it. The makefile uses a sentinel file to indicate that the
|
||||
docker image has been build, and can be reused.
|
||||
|
||||
make docker-test-everything
|
||||
|
||||
|
||||
|
||||
How does this work
|
||||
------------------
|
||||
|
||||
The Dockerfile makes heavy use of multistage
|
||||
builds. This allows the various output containers to build on the same
|
||||
earlier stages.
|
||||
|
||||
There are two ``base`` images. A ``minimal`` image, which contains
|
||||
compiled dependencies and ruby. And an ``everything`` image which brings
|
||||
in scripting systems like ``python`` and ``perl``. These are split to
|
||||
allow a smaller ``minimal`` image in cases where building scripting
|
||||
language packages are not needed.
|
||||
|
||||
The Dockerfile the argument ``BASE_ENV`` to specify what base image to
|
||||
use. This can be set to either ``minimal`` or ``everything``. If
|
||||
unspecified, it defaults to ``everything``
|
||||
|
||||
We want to use the same set of base images for both the ``rspec``
|
||||
testing, as well as the run time containerization. We do this by using
|
||||
the ``TARGET`` argument to select which container to build.
|
||||
|
||||
The makefile encodes this logic with two pattern rules.
|
||||
|
|
@ -467,11 +467,11 @@ describe FPM::Package::Deb do
|
|||
end # after
|
||||
|
||||
it "it should output bit-for-bit identical packages" do
|
||||
lamecmds = []
|
||||
lamecmds << "ar" if not ar_cmd_deterministic?
|
||||
lamecmds << "tar" if not tar_cmd_supports_sort_names_and_set_mtime?
|
||||
if not lamecmds.empty?
|
||||
skip("fpm searched for variants of #{lamecmds.join(", ")} that support(s) deterministic archives, but found none, so can't test reproducibility.")
|
||||
cmds = []
|
||||
cmds << "ar" if not ar_cmd_deterministic?
|
||||
cmds << "tar" if not tar_cmd_supports_sort_names_and_set_mtime?
|
||||
if not cmds.empty?
|
||||
skip("fpm searched for variants of [#{cmds.join(", ")}] that support(s) deterministic archives, but found none, so can't test reproducibility.")
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,8 @@ describe FPM::Package::Python do
|
|||
|
||||
context "python_scripts_executable is set" do
|
||||
it "should have scripts with a custom hashbang line" do
|
||||
pending("Disabled on travis-ci because it always fails, and there is no way to debug it?") if is_travis
|
||||
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")
|
||||
|
||||
subject.attributes[:python_scripts_executable] = "fancypants"
|
||||
# Newer versions of Django require Python 3.
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@ require "spec_setup"
|
|||
require "fpm" # local
|
||||
require "English" # for $CHILD_STATUS
|
||||
|
||||
is_old_ruby = (RUBY_VERSION =~ /^((1\.)|(2\.0))/)
|
||||
IS_OLD_RUBY = (RUBY_VERSION =~ /^((1\.)|(2\.0))/)
|
||||
|
||||
describe FPM::Package::Snap do
|
||||
let(:target) { Stud::Temporary.pathname + ".snap" }
|
||||
before do
|
||||
skip("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
skip("Missing program 'mksquashfs'") unless program_exists?("mksquashfs")
|
||||
end
|
||||
after do
|
||||
subject.cleanup
|
||||
File.unlink(target) if File.exist?(target)
|
||||
|
|
@ -21,7 +25,7 @@ describe FPM::Package::Snap do
|
|||
end
|
||||
|
||||
it "should have a default output usable as a filename" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
# This is the default filename commonly produced by snapcraft
|
||||
insist { subject.to_s } == "name_123-100_all.snap"
|
||||
end
|
||||
|
|
@ -32,7 +36,7 @@ describe FPM::Package::Snap do
|
|||
end
|
||||
|
||||
it "should not include iteration if it is nil" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
# This is the default filename commonly produced by snapcraft
|
||||
expect(subject.to_s).to(be == "name_123_all.snap")
|
||||
end
|
||||
|
|
@ -89,32 +93,32 @@ describe FPM::Package::Snap do
|
|||
end
|
||||
|
||||
it "should have the correct name" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.name } == original.name
|
||||
end
|
||||
|
||||
it "should have the correct version" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.version } == original.version
|
||||
end
|
||||
|
||||
it "should have the correct description" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.description } == original.description
|
||||
end
|
||||
|
||||
it "should have the correct architecture" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.architecture } == original.architecture
|
||||
end
|
||||
|
||||
it "should have the correct apps" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.attributes[:snap_apps] } == original.attributes[:snap_apps]
|
||||
end
|
||||
|
||||
it "should have the correct hooks" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.attributes[:snap_hooks] } == original.attributes[:snap_hooks]
|
||||
end
|
||||
end
|
||||
|
|
@ -143,38 +147,38 @@ describe FPM::Package::Snap do
|
|||
end
|
||||
|
||||
it "should have the custom name" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.name } == "custom-name"
|
||||
end
|
||||
|
||||
it "should have the custom version" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.version } == "custom-version"
|
||||
end
|
||||
|
||||
it "should have the custom description" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.description } == "custom-summary\ncustom-description"
|
||||
end
|
||||
|
||||
it "should have the custom architecture" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.architecture } == "custom-architecture"
|
||||
end
|
||||
|
||||
it "should have the custom apps" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.attributes[:snap_apps] } == []
|
||||
end
|
||||
|
||||
it "should have the custom hooks" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
insist { input.attributes[:snap_hooks] } == []
|
||||
end
|
||||
end
|
||||
|
||||
it "should support specifying confinement" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
original.attributes[:snap_confinement] = "test-confinement"
|
||||
|
||||
original.output(target)
|
||||
|
|
@ -184,7 +188,7 @@ describe FPM::Package::Snap do
|
|||
end
|
||||
|
||||
it "should support specifying grade" do
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if is_old_ruby
|
||||
pending("Ruby 1.x and 2.0.x are unsupported for Snap because it lacks Psych::safe_load") if IS_OLD_RUBY
|
||||
original.attributes[:snap_grade] = "test-grade"
|
||||
|
||||
original.output(target)
|
||||
|
|
|
|||
Loading…
Reference in New Issue