Cross package maker. DEB/RPM generation or conversion. Derived from jordansissel/fpm.

⌈⌋ branch:  cross package maker


Check-in [1e5dbadf47]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
SHA1 Hash:1e5dbadf476425f8858217a8803dadea4850b8f2
Date: 2012-02-23 07:59:31
User: jls
Comment:- start major refactoring. Design first, this time. With tests.
Tags And Properties
  • sym-trunk inherited from [2b439be7d6]
Context
2012-02-24
07:43
[40571c6988] - move older minitest tests away until they can be refactored to the new api (user: jls, tags: trunk)
2012-02-23
07:59
[1e5dbadf47] - start major refactoring. Design first, this time. With tests. (user: jls, tags: trunk)
2012-02-22
23:10
[35ee49c8a5] - update changelist for 0.3.12 (user: jls, tags: trunk, v0.3.12)
Changes

Added Gemfile.







>
>
>
1
2
3
source :rubygems

gemspec

Changes to fpm.gemspec.

6
7
8
9
10
11
12
13
14
15
16


17
18
19
20
21
22
23
24
25
26
27
  end

  files << "LICENSE"
  files << "CONTRIBUTORS"
  files << "CHANGELIST"

  spec.name = "fpm"
  spec.version = "0.3.12"
  spec.summary = "fpm - package building and mangling"
  spec.description = "Convert directories, rpms, python eggs, rubygems, and more to rpms, debs, solaris packages and more. Win at package management without wasting pointless hours debugging bad rpm specs!"
  spec.add_dependency("json")


  spec.files = files
  spec.require_paths << "lib"
  spec.bindir = "bin"
  spec.executables << "fpm"
  spec.executables << "fpm-npm"

  spec.author = "Jordan Sissel"
  spec.email = "jls@semicomplete.com"
  spec.homepage = "https://github.com/jordansissel/fpm"
end








|



>
>











6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  end

  files << "LICENSE"
  files << "CONTRIBUTORS"
  files << "CHANGELIST"

  spec.name = "fpm"
  spec.version = "0.4.0"
  spec.summary = "fpm - package building and mangling"
  spec.description = "Convert directories, rpms, python eggs, rubygems, and more to rpms, debs, solaris packages and more. Win at package management without wasting pointless hours debugging bad rpm specs!"
  spec.add_dependency("json")
  spec.add_dependency("backports", "2.3.0")
  spec.add_development_dependency("rush")
  spec.files = files
  spec.require_paths << "lib"
  spec.bindir = "bin"
  spec.executables << "fpm"
  spec.executables << "fpm-npm"

  spec.author = "Jordan Sissel"
  spec.email = "jls@semicomplete.com"
  spec.homepage = "https://github.com/jordansissel/fpm"
end

Changes to lib/fpm/package.rb.

1
2
3
4
5
6
7
8
9
10
11
..
15
16
17
18
19
20
21
22


23
24
25
26
27
28
29
..
36
37
38
39
40
41
42

43
44
45
46
47
48
49
..
65
66
67
68
69
70
71
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

94
95
96
97
98
99
100
101



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122


123
124
125
126
127
128

129
130
131
132

133
134
135
136











137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
require "fpm/namespace"
require "socket" # for Socket.gethostname
require "logger"
require "find" # for Find.find (directory walking)

class FPM::Package
  # The name of this package
  attr_accessor :name

  # The version of this package (the upstream version)
  attr_accessor :version
................................................................................
  # style so standard comparisions wouldn't work.
  attr_accessor :epoch

  # The iteration of this package.
  #   Debian calls this 'release' and is the last '-NUMBER' in the version
  #   RedHat has this as 'Release' in the .spec file
  #   FreeBSD calls this 'PORTREVISION'
  # If left unpicked, it defaults to 1.


  attr_accessor :iteration

  # Who maintains this package? This could be the upstream author
  # or the package maintainer. You pick.
  attr_accessor :maintainer

  # URL for this package.
................................................................................
  # FreeBSD would put this in /usr/ports/<category>/...
  attr_accessor :category

  # A identifier representing the license. Any string is fine.
  attr_accessor :license

  # A identifier representing the vendor. Any string is fine.

  attr_accessor :vendor

  # What architecture is this package for?
  attr_accessor :architecture

  # Array of dependencies.
  attr_accessor :dependencies
................................................................................

  # hash of paths for maintainer/package scripts (postinstall, etc)
  attr_accessor :scripts

  # Array of configuration files
  attr_accessor :config_files

  # Package path prefix

  attr_accessor :prefix

	# target-specific settings
	attr_accessor :settings

  def initialize(source, params={})
    @source = source
    @logger = Logger.new(STDERR)
    @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN

    @name = source[:name] # || fail

    # Default version is 1.0 in case nobody told us a specific version.
    @version = source[:version] || "1.0"
    @epoch = source[:epoch]

    @dependencies = source[:dependencies] || []
    # Iteration can be nil. If nil, the fpm package implementation is expected
    # to handle any default value that should be instead.
    @iteration = source[:iteration]
    @url = source[:url] || "http://nourlgiven.example.com/no/url/given"

    @category = source[:category] || "default"
    @license = source[:license] || "unknown"
    @vendor = source[:vendor] || "none"
    #@maintainer = source[:maintainer] || "<#{ENV["USER"]}@#{Socket.gethostname}>"
    @maintainer = source[:maintainer]

    # Default maintainer if none given.
    if @maintainer.nil? or @maintainer.empty?



      # Reference
      # http://www.debian.org/doc/manuals/maint-guide/first.en.html
      # http://wiki.debian.org/DeveloperConfiguration
      # https://github.com/jordansissel/fpm/issues/37
      if ENV.include?("DEBEMAIL") and ENV.include?("DEBFULLNAME")
        # Use DEBEMAIL and DEBFULLNAME as the default maintainer if available.
        @maintainer = "#{ENV["DEBFULLNAME"]} <#{ENV["DEBEMAIL"]}>"
      else
        # TODO(sissel): Maybe support using 'git config' for a default as well?
        # git config --get user.name, etc can be useful.
        #
        # Otherwise default to user@currenthost
        @maintainer = "<#{ENV["USER"]}@#{Socket.gethostname}>"
      end
    end

    # If @architecture is nil, the target package should provide a default.
    # Special 'architecture' values include "all" (aka rpm's noarch, debian's all)
    # Another special includes "native" which will be the current platform's arch.
    @architecture = source[:architecture]
    @description = source[:description] || "no description given"


    @provides = source[:provides] || []
    @replaces = source[:replaces] || []
    @conflicts = source[:conflicts] || []
    @scripts = source[:scripts]
    @config_files = source[:config_files] || []
    @prefix = source[:prefix] || "/"


    # Target-specific settings, mirrors :settings metadata in FPM::Source
    @settings = params[:settings] || {}
  end # def initialize


  # nobody needs md5sums by default.
  def needs_md5sums
    false











  end # def needs_md5sums

  # TODO [Jay]: make this better...?
  def type
    self.class.name.split(':').last.downcase
  end # def type

  def template(path=nil)
    path ||= "#{type}.erb"
    @logger.info("Reading template: #{path}")
    tpl = File.read("#{FPM::DIRS[:templates]}/#{path}")
    return ERB.new(tpl, nil, "-")
  end # def template

  def render_spec
    # find all files in paths given.
    paths = []
    @source.paths.each do |path|
      Find.find(path) { |p| paths << p }
    end
    #@logger.info(:paths => paths.sort)
    template.result(binding)
  end # def render_spec

  # Default specfile generator just makes one specfile, whatever that is for
  # this package.
  def generate_specfile(builddir)
    File.open(specfile(builddir), "w") do |f|
      f.puts render_spec
    end
  end # def generate_specfile

  def default_output
    if iteration
      "#{name}-#{version}-#{iteration}.#{architecture}.#{type}"
    else
      "#{name}-#{version}.#{architecture}.#{type}"
    end
  end # def default_output

  def fixpath(path)
    if path[0,1] != "/"
      path = File.join(@source.root, path)
    end
    return path if File.symlink?(path)
    @logger.info(:fixpath => path)
    realpath = Pathname.new(path).realpath.to_s
    re = Regexp.new("^#{Regexp.escape(@source.root)}")
    realpath.gsub!(re, "")
    @logger.info(:fixpath_result => realpath)
    return realpath
  end # def fixpath
end # class FPM::Package



|







 







|
>
>







 







>







 







|
>
|

<
|

|
<



<
<

|
|
<
|
<
<
|
<
>
|
|
|
<
<

<
<
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
<





|
|
>
>
|
<
|
|
|
|
>

<
<
|
>
|
<
|
<
>
>
>
>
>
>
>
>
>
>
>
|






|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
..
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
..
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
..
68
69
70
71
72
73
74
75
76
77
78

79
80
81

82
83
84


85
86
87

88


89

90
91
92
93


94


95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120

121
122
123
124
125
126


127
128
129

130

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181













require "fpm/namespace"
require "socket" # for Socket.gethostname
require "logger"
require "tmpdir"

class FPM::Package
  # The name of this package
  attr_accessor :name

  # The version of this package (the upstream version)
  attr_accessor :version
................................................................................
  # style so standard comparisions wouldn't work.
  attr_accessor :epoch

  # The iteration of this package.
  #   Debian calls this 'release' and is the last '-NUMBER' in the version
  #   RedHat has this as 'Release' in the .spec file
  #   FreeBSD calls this 'PORTREVISION'
  #
  # Iteration can be nil. If nil, the fpm package implementation is expected
  # to handle any default value that should be instead.
  attr_accessor :iteration

  # Who maintains this package? This could be the upstream author
  # or the package maintainer. You pick.
  attr_accessor :maintainer

  # URL for this package.
................................................................................
  # FreeBSD would put this in /usr/ports/<category>/...
  attr_accessor :category

  # A identifier representing the license. Any string is fine.
  attr_accessor :license

  # A identifier representing the vendor. Any string is fine.
  # This is usually who produced the software.
  attr_accessor :vendor

  # What architecture is this package for?
  attr_accessor :architecture

  # Array of dependencies.
  attr_accessor :dependencies
................................................................................

  # hash of paths for maintainer/package scripts (postinstall, etc)
  attr_accessor :scripts

  # Array of configuration files
  attr_accessor :config_files

  # Any other attributes specific to this package.
  # This is where you'd put rpm, deb, or other specific attributes.
  attr_accessor :attributes


  private

  def initialize

    @logger = Logger.new(STDERR)
    @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN



    # Default version is 1.0 in case nobody told us a specific version.
    @version = 1.0
    @epoch = 1

    @dependencies = []


    @iteration = nil

    @url = nil
    @category = "default"
    @license = "unknown"
    @vendor = "none"





    # Attributes for this specific package 
    @attributes = {}

    # Reference
    # http://www.debian.org/doc/manuals/maint-guide/first.en.html
    # http://wiki.debian.org/DeveloperConfiguration
    # https://github.com/jordansissel/fpm/issues/37
    if ENV.include?("DEBEMAIL") and ENV.include?("DEBFULLNAME")
      # Use DEBEMAIL and DEBFULLNAME as the default maintainer if available.
      @maintainer = "#{ENV["DEBFULLNAME"]} <#{ENV["DEBEMAIL"]}>"
    else
      # TODO(sissel): Maybe support using 'git config' for a default as well?
      # git config --get user.name, etc can be useful.
      #
      # Otherwise default to user@currenthost
      @maintainer = "<#{ENV["USER"]}@#{Socket.gethostname}>"

    end

    # If @architecture is nil, the target package should provide a default.
    # Special 'architecture' values include "all" (aka rpm's noarch, debian's all)
    # Another special includes "native" which will be the current platform's arch.
    @architecture = "all"
    @description = "no description given"

    # TODO(sissel): Implement provides, requires, conflicts, etc later.
    #@provides = []

    #@conflicts = source[:conflicts] || []
    #@scripts = source[:scripts]
    #@config_files = source[:config_files] || []
    #@prefix = source[:prefix] || "/"
  end # def initialize



  # Add a new source to this package.
  # The exact behavior depends on the kind of package being managed.
  #

  # For instance: 

  #
  # * for FPM::Package::Dir, << expects a path to a directory or files.
  # * for FPM::Package::RPM, << expects a path to an rpm.
  #
  # The idea is that you can keep pumping in new things to a package
  # for later conversion or output.
  #
  # Implementations are expected to put files relevant to the 'input' in the
  # staging_path
  def <<(input)
    raise NotImplementedError.new
  end # def <<

  # TODO [Jay]: make this better...?
  def type
    self.class.name.split(':').last.downcase
  end # def type

  # Convert this package to a new package type
  def convert(klass)
    pkg = klass.new
    pkg.instance_variable_set(:@staging_path, staging_path)

    # copy other bits
    ivars = [
      :architecture, :attributes, :category, :config_files, :conflicts,
      :dependencies, :description, :epoch, :iteration, :license, :maintainer,
      :name, :provides, :replaces, :scripts, :url, :vendor, :version
    ]
    ivars.each do |ivar|
      pkg.instance_variable_set(ivar, instance_variable_get(ivar))
    end

    return pkg
  end # def convert

  def output(path)
    raise NotImplementedError.new("This must be implemented by FPM::Package subclasses")
  end # def output

  def staging_path
    @staging_path ||= ::Dir.mktmpdir(File.join(::Dir.pwd, "package-#{type}-staging"))
  end # def staging_path

  # Clean up any temporary storage used by this class.
  def cleanup
    FileUtils.rm_r(staging_path)
  end # def cleanup

  public(:type, :initialize, :convert, :output, :<<, :cleanup, :staging_path)
end # class FPM::Package













Added lib/fpm/package/dir.rb.



























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
require "fpm/package"
require "backports"
require "fileutils"
require "find"

class FPM::Package::Dir < FPM::Package
  private

  def <<(path)
    @paths ||= []
    @paths << path

    clone(path, staging_path)
  end # def <<

  def output(dir)
    dir = File.expand_path(dir)
    @paths.each do |path|
      ::Dir.chdir(staging_path) do
        clone(path, dir)
      end
    end
  end

  private
  # Copy a file or directory to a destination
  #
  # This is special because it respects the full path of the source.
  # Aditionally, hardlinks will be used instead of copies.
  #
  # Example:
  #
  #     clone("/tmp/hello/world", "/tmp/example")
  #
  # The above will copy, recursively, /tmp/hello/world into
  # /tmp/example/hello/world
  def clone(source, destination)
    # Copy all files from 'path' into staging_path

    ::Dir.chdir(@attributes[:chdir] || ".") do
      p :chdir => ::Dir.pwd, :source => source
      Find.find(source).each do |file|
        next if source == file # ignore the directory itself
        # Translate file paths with attributes like 'prefix' and 'chdir'
        if @attributes[:prefix]
          target = File.join(destination, @attributes[:prefix], file)
        else
          target = File.join(destination, file)
        end

        copy(file, target)
      end
    end
  end # def clone

  def copy(source, destination)
    directory = File.dirname(destination)
    if !File.directory?(directory)
      FileUtils.mkdir_p(directory)
    end

    # Create a directory if this path is a directory
    if File.directory?(source)
      FileUtils.mkdir(destination)
    else
      # Otherwise try copying the file.
      begin
        File.link(source, destination)
      rescue Errno::EXDEV
        # Hardlink attempt failed, copy it instead
        FileUtils.copy(source, destination)
      end
    end
  end # def copy

  public(:<<, :output)
end # class FPM::Package::Dir

Changes to lib/fpm/source.rb.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

144
145
146
    vendor
  ).each do |attr|
    attr = :"#{attr}"
    define_method(attr) { self[attr] }
    define_method(:"#{attr}=") { |v| self[attr] = v}
  end

  def dependencies
    self[:dependencies] ||= []
  end

  attr_reader :paths
  attr_accessor :root

  def initialize(paths, root, params={})
    @logger = Logger.new(STDERR)
    @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN

    @paths = paths
    @root = root

    self[:suffix] = params[:suffix]
    self[:settings] = params[:settings]

    get_source(params)
    get_metadata

    # override the inferred data with the passed-in data
    params.each do |k,v|
      self[k] = v if v != nil
    end
  end # def initialize

  # this method should take the paths and root and infer as much
  # about the package as it can.
  def get_metadata
    raise NoMethodError,
      "Please subclass FPM::Source and define get_metadata"
  end # def get_metadata

  # This method should be overridden by package sources that need to do any
  # kind of fetching.
  def get_source(params)
    # noop by default
  end # def get_source

  def make_tarball!(tar_path, builddir)
    raise NoMethodError,
      "Please subclass FPM::Source and define make_tarball!(tar_path)"
  end




  def metadata
    @metadata ||= {}
  end

  def [](key)
    metadata[key.to_sym]
  end

  def []=(key,val)
    metadata[key.to_sym] = val
  end

  # MySourceClass.new('/tmp/build').package(FPM::Deb).assemble(params)
  def package(pkg_cls)
    pkg_cls.new(self)
  end

  private
  def tar(output, paths, chdir=".")
    dirs = []

    # Include all directory entries at the top of the tarball
    paths = [ paths ] if paths.is_a? String
    paths.each do |path|
      while path != "/" and path != "."
        dirs << path if !dirs.include?(path)
        path = File.dirname(path)
      end
    end # paths.each

    # Want directories to be sorted thusly: [ "/usr", "/usr/bin" ]
    # Why? tar and some package managers sometimes fail if the tar is created
    # like: [ "/opt/fizz", "/opt" ]
    # dpkg -i will fail if /opt doesn't exist, sorting it by length ensures
    # /opt is created before /opt/fizz.
    dirs.sort! { |a,b| a.size <=> b.size }
    paths.sort! { |a,b| a.size <=> b.size }


    # Solaris's tar is pretty neutered, so implement --exclude and such
    # ourselves.
    # TODO(sissel): May need to implement our own tar file generator
    # so we can enforce file ownership. Again, solaris' tar doesn't support
    # --owner, etc.
    #paths = []
    #dirs.each do |dir|
      #Dir.glob(File.join(dir, "**", "*")).each do |path|
        #next if excludesFile.fnmatch?(
      #end
    #end

    excludes = self[:exclude].map { |e| ["--exclude", e] }.flatten

    # TODO(sissel): To properly implement excludes as regexps, we
    # will need to find files ourselves. That may be more work
    # than it is worth. For now, rely on tar's --exclude.
    dir_tar = [tar_cmd, "--owner=0", "--group=0" ] \
              + excludes \
              + ["-cf", output, "--no-recursion" ]

    # Only if directories and paths do not have duplicates ...
    dirs -= paths

    if dirs.any?
      ::Dir.chdir(chdir) do
        safesystem *(dir_tar += dirs)
      end
    end

    files_tar = [ tar_cmd ] \
                + excludes \
                + [ "--owner=0", "--group=0", "-rf", output ] \
                + paths
    ::Dir.chdir(chdir) do
      safesystem(*files_tar)
    end

  end # def tar

end # class FPM::Source







<
<
<
<
<
<
<
|


<
<
<
<
<
<
<
<
<
<
<
<
<
<


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
>
|


17
18
19
20
21
22
23







24
25
26














27
28


















29
30
31
32











































































33
34
35
36
    vendor
  ).each do |attr|
    attr = :"#{attr}"
    define_method(attr) { self[attr] }
    define_method(:"#{attr}=") { |v| self[attr] = v}
  end








  def initialize
    @logger = Logger.new(STDERR)
    @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN














  end # def initialize



















  # Add a new argument to this source
  # The effect of this is specific to the source's implementation,
  # but in general this means you are adding something to this source.
  def <<(arg)











































































    raise NotImplementedError.new
  end # def <<

end # class FPM::Source

Deleted test/Makefile.

1
2
3
4
5
6
7
8
9
10
11
TESTS=$(shell git ls-files '*.test')

.PHONY: test
test: $(TESTS)

.PHONY: $(TESTS)
$(TESTS):
	@bash test.sh $@

clean:
	rm *.deb *.rpm *.gem
<
<
<
<
<
<
<
<
<
<
<






















Added test/all.rb.

















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require "rubygems"
require "minitest/spec"
require "minitest/autorun"

# Get coverage report
require "simplecov"
SimpleCov.start

# Add '../lib' to the require path.
$: << File.join(File.dirname(__FILE__), "..", "lib")

def use(path)
  puts "Loading tests from #{path}"
  require File.expand_path(path)
end

dirname = File.dirname(__FILE__)
use File.join(dirname, "docs.rb")

# Load tests from ./*/**/*.rb (usually ./libraryname/....)
glob = File.join(dirname, "*", "**", "*.rb")
Dir.glob(glob).each do |path|
  use path
end

Deleted test/dir-deb-with-debconf.out.

1
2
       0 bytes,     0 lines   *  config               
       0 bytes,     0 lines      templates            
<
<




Deleted test/dir-deb-with-debconf.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

run() {
  mkdir -p $tmpdir/prefix
  touch $tmpdir/config
  touch $tmpdir/templates

  fpm -s dir -t deb -n testing -a all \
  --deb-config $tmpdir/config \
  --deb-templates $tmpdir/templates \
  $tmpdir/prefix

  file=testing_1.0_all.deb
  dpkg -I $file | grep "\(config\)\|\(templates\)" > $output

  rm $file
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































Deleted test/dir-deb-with-prefix.out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
./
./opt/
./opt/foo/
./opt/foo/bar/
./opt/foo/bar/a/
./opt/foo/bar/a/d/
./opt/foo/bar/a/d/hello
./opt/foo/bar/a/e/
./opt/foo/bar/a/f/
./opt/foo/bar/a/hello
./opt/foo/bar/b/
./opt/foo/bar/b/d/
./opt/foo/bar/b/e/
./opt/foo/bar/b/f/
./opt/foo/bar/c/
./opt/foo/bar/c/d/
./opt/foo/bar/c/d/hello
./opt/foo/bar/c/e/
./opt/foo/bar/c/f/
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































Deleted test/dir-deb-with-prefix.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

run() {
  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
  touch $tmpdir/a/hello
  touch $tmpdir/a/d/hello
  touch $tmpdir/c/d/hello

  prefix=/opt/foo/bar

  fpm -s dir -t deb -n testing -a all --prefix $prefix -C $tmpdir 

  file=testing_1.0_all.deb
  dpkg -c $file | awk '{$1=$2=$3=$4=$5="";print}' | sed -e 's/^ *//' | sort > $output

  rm $file
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































Deleted test/dir-deb.out.template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
tmp/
tmp/TMPDIR/
tmp/TMPDIR/a/
tmp/TMPDIR/a/d/
tmp/TMPDIR/a/d/hello
tmp/TMPDIR/a/e/
tmp/TMPDIR/a/f/
tmp/TMPDIR/a/hello
tmp/TMPDIR/b/
tmp/TMPDIR/b/d/
tmp/TMPDIR/b/e/
tmp/TMPDIR/b/f/
tmp/TMPDIR/c/
tmp/TMPDIR/c/d/
tmp/TMPDIR/c/d/hello
tmp/TMPDIR/c/e/
tmp/TMPDIR/c/f/
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































Deleted test/dir-deb.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

run() {
  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
  touch $tmpdir/a/hello
  touch $tmpdir/a/d/hello
  touch $tmpdir/c/d/hello

  prefix=/opt/foo/bar

  fpm -s dir -t deb -n testing -a all $tmpdir

  file=testing_1.0_all.deb
  dpkg -c $file | awk '{$1=$2=$3=$4=$5="";print}' | sed -e 's/^ *//' | sort > $output
  #ar p $file data.tar.gz | tar -ztf - | sort > $output
  sed -e "s,TMPDIR,$(basename $tmpdir)," $expected.template > $expected

  rm $file
}

clean() {
  rm $expected
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































Deleted test/dir-rpm-with-prefix.out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/opt/foo/bar
/opt/foo/bar/a
/opt/foo/bar/a/d
/opt/foo/bar/a/d/hello
/opt/foo/bar/a/e
/opt/foo/bar/a/f
/opt/foo/bar/a/hello
/opt/foo/bar/b
/opt/foo/bar/b/d
/opt/foo/bar/b/e
/opt/foo/bar/b/f
/opt/foo/bar/c
/opt/foo/bar/c/d
/opt/foo/bar/c/d/hello
/opt/foo/bar/c/e
/opt/foo/bar/c/f
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































Deleted test/dir-rpm-with-prefix.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

run() {
  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
  touch $tmpdir/a/hello
  touch $tmpdir/a/d/hello
  touch $tmpdir/c/d/hello

  prefix=/opt/foo/bar

  fpm -s dir -t rpm -n testing -a all --prefix $prefix -C $tmpdir 

  rpm -qlp testing-1.0-1.noarch.rpm > $output
  rm testing-1.0-1.noarch.rpm
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























Deleted test/dir-rpm.out.template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/tmp/TMPDIR
/tmp/TMPDIR/a
/tmp/TMPDIR/a/d
/tmp/TMPDIR/a/d/hello
/tmp/TMPDIR/a/e
/tmp/TMPDIR/a/f
/tmp/TMPDIR/a/hello
/tmp/TMPDIR/b
/tmp/TMPDIR/b/d
/tmp/TMPDIR/b/e
/tmp/TMPDIR/b/f
/tmp/TMPDIR/c
/tmp/TMPDIR/c/d
/tmp/TMPDIR/c/d/hello
/tmp/TMPDIR/c/e
/tmp/TMPDIR/c/f
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































Deleted test/dir-rpm.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

run() {
  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
  touch $tmpdir/a/hello
  touch $tmpdir/a/d/hello
  touch $tmpdir/c/d/hello

  fpm -s dir -t rpm -n testing -a all $tmpdir

  file=testing-1.0-1.noarch.rpm
  rpm -qlp $file > $output
  sed -e "s,TMPDIR,$(basename $tmpdir)," $expected.template > $expected

  rm $file
}

clean() {
  rm $expected
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































Added test/docs.rb.



















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
require "rubygems"                                                                                               
require "yard"                                                                                                   
require File.join(File.expand_path(File.dirname(__FILE__)), "testing")
require "minitest/autorun"

describe "documentation tests" do
  before do
    # Use YARD to parse all ruby files found in '../lib'
    libdir = File.join(File.dirname(__FILE__), "..", "lib")
    YARD::Registry.load(Dir.glob(File.join(libdir, "**", "*.rb")))
    @registry = YARD::Registry.all
  end

  test "All classes, methods, modules, and constants must be documented" do
    # Note, the 'find the undocumented things' code here is 
    # copied mostly from: YARD 0.7.5's lib/yard/cli/stats.rb
    #
    # Find all undocumented classes, modules, and constants
    undocumented = @registry.select do |o| 
      [:class, :module, :constant].include?(o.type) && o.docstring.blank?
    end

    # Find all undocumented methods
    methods = @registry.select { |m| m.type == :method }
    methods.reject! { |m| m.is_alias? || !m.is_explicit? }
    undocumented += methods.select do |m| 
      m.docstring.blank? && !m.overridden_method
    end

    if (undocumented.length > 0)
      message = ["The following are not documented"]
      undocumented.each do |o|
        message << "* #{o.type.to_s} #{o.to_s} <#{o.file}:#{o.line}>"
      end

      flunk(message.join("\n"))
    else
      pass
    end
  end
end

Added test/fpm/package/dir.rb.



















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
require "rubygems"
require File.join(File.dirname(File.expand_path(__FILE__)), "..", "..", "testing")
$: << File.join(File.dirname(File.expand_path(__FILE__)), "..", "..", "..", "lib")
require "minitest/autorun"
require "tmpdir"
require "fileutils"
require "fpm/package/dir"
require "rush" # for simple file stuff

describe FPM::Package::Dir do
  before do
    @source = FPM::Package::Dir.new
    @rush = Rush::Box.new("localhost")
    @tmpdir = @rush[::Dir.mktmpdir("package-test-tmpdir")]
    @output = @rush[::Dir.mktmpdir("package-test-output")]
  end # before

  after do
    @source.cleanup
    FileUtils.rm_r(@tmpdir.full_path)
    FileUtils.rm_r(@output.full_path)
  end # after

  test "adding a single file" do
    file = @tmpdir["hello"]
    file.write "Hello world"
    @source << @tmpdir.full_path

    @source.output(@output.full_path)
    assert_equal(@output[File.join(".", file.full_path)].contents,
                 file.contents, "The file #{@tmpdir["hello"].full_path} should appear in the output")
  end

  test "single file in a directory" do
    dir = @tmpdir.create_dir("a/b/c")
    file = dir.create_file("hello")
    file.write "Hello world"
    @source << @tmpdir.full_path

    @source.output(@output.full_path)
    assert_equal(@output[File.join(".", file.full_path)].contents,
                 file.contents, "The file #{@tmpdir["a/b/c/hello"].full_path} should appear in the output")
  end

  test "multiple files" do
    dir = @tmpdir.create_dir("a/b/c")
    files = rand(50).times.collect do |i|
      dir.create_file("hello-#{i}")
    end
    files.each { |f| f.write(rand(1000)) }

    @source << @tmpdir.full_path
    @source.output(@output.full_path)

    files.each do |file|
      assert_equal(@output[File.join(".", file.full_path)].contents,
                   file.contents, "The file #{file.full_path} should appear in the output")
    end
  end

  test "single file with prefix" do
    prefix = @source.attributes[:prefix] = "/usr/local"
    file = @tmpdir["hello"]
    file.write "Hello world"
    @source << @tmpdir.full_path

    @source.output(@output.full_path)

    expected_path = File.join(".", prefix, file.full_path)
    assert_equal(@output[expected_path].contents,
                 file.contents, "The file #{@tmpdir["hello"].full_path} should appear in the output")
  end

  test "single file with prefix and chdir" do
    prefix = @source.attributes[:prefix] = "/usr/local"
    chdir = @source.attributes[:chdir] = @tmpdir.full_path
    file = @tmpdir["hello"]
    file.write "Hello world"
    @source << "." # since we chdir, copy the entire root

    @source.output(@output.full_path)

    # path relative to the @output directory.
    expected_path = File.join(".", prefix, file.name)
    assert_equal(@output[expected_path].contents,
                 file.contents, "The file #{@tmpdir["hello"].full_path} should appear in the output")
  end

end # describe FPM::Package::Dir

Deleted test/gem-deb.out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
./usr/
./usr/lib/
./usr/lib/ruby/
./usr/lib/ruby/gems/
./usr/lib/ruby/gems/1.8/
./usr/lib/ruby/gems/1.8/bin/
./usr/lib/ruby/gems/1.8/bin/rails
./usr/lib/ruby/gems/1.8/cache/
./usr/lib/ruby/gems/1.8/cache/rails-3.1.0.gem
./usr/lib/ruby/gems/1.8/doc/
./usr/lib/ruby/gems/1.8/gems/
./usr/lib/ruby/gems/1.8/gems/rails-3.1.0/
./usr/lib/ruby/gems/1.8/gems/rails-3.1.0/bin/
./usr/lib/ruby/gems/1.8/gems/rails-3.1.0/bin/rails
./usr/lib/ruby/gems/1.8/specifications/
./usr/lib/ruby/gems/1.8/specifications/rails-3.1.0.gemspec
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































Deleted test/gem-deb.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
RAILS_VERSION=3.1.0

run() {
  # Force the gem installation path to match the one of the expected output
  export GEM_HOME=/usr/lib/ruby/gems/1.8
  
  fpm -s gem -t deb -v $RAILS_VERSION rails

  file=rubygem-rails_${RAILS_VERSION}_all.deb
  dpkg -c $file | awk '{$1=$2=$3=$4=$5="";print}' | sed -e 's/^ *//' | sort > $output
  rm $file
}

clean() {
  rm rails-${RAILS_VERSION}.gem
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































Added test/testing.rb.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
require "rubygems"
require "minitest/spec"

# Add '../lib' to the require path.
$: << File.join(File.dirname(__FILE__), "..", "lib")

# I don't really like monkeypatching, but whatever, this is probably better
# than overriding the 'describe' method.
class MiniTest::Spec
  class << self
    # 'it' sounds wrong, call it 'test'
    alias :test :it
  end
end