Skip to content
This repository
Browse code

- start major refactoring. Design first, this time. With tests.

  • Loading branch information...
commit f7187f1e9ba18b12b3bca109dbe86731c148e584 1 parent bb76bc2
Jordan Sissel authored February 22, 2012
3  Gemfile
... ...
@@ -0,0 +1,3 @@
  1
+source :rubygems
  2
+
  3
+gemspec
4  fpm.gemspec
@@ -10,10 +10,12 @@ Gem::Specification.new do |spec|
10 10
   files << "CHANGELIST"
11 11
 
12 12
   spec.name = "fpm"
13  
-  spec.version = "0.3.12"
  13
+  spec.version = "0.4.0"
14 14
   spec.summary = "fpm - package building and mangling"
15 15
   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!"
16 16
   spec.add_dependency("json")
  17
+  spec.add_dependency("backports", "2.3.0")
  18
+  spec.add_development_dependency("rush")
17 19
   spec.files = files
18 20
   spec.require_paths << "lib"
19 21
   spec.bindir = "bin"
186  lib/fpm/package.rb
... ...
@@ -1,7 +1,7 @@
1 1
 require "fpm/namespace"
2 2
 require "socket" # for Socket.gethostname
3 3
 require "logger"
4  
-require "find" # for Find.find (directory walking)
  4
+require "tmpdir"
5 5
 
6 6
 class FPM::Package
7 7
   # The name of this package
@@ -19,7 +19,9 @@ class FPM::Package
19 19
   #   Debian calls this 'release' and is the last '-NUMBER' in the version
20 20
   #   RedHat has this as 'Release' in the .spec file
21 21
   #   FreeBSD calls this 'PORTREVISION'
22  
-  # If left unpicked, it defaults to 1.
  22
+  #
  23
+  # Iteration can be nil. If nil, the fpm package implementation is expected
  24
+  # to handle any default value that should be instead.
23 25
   attr_accessor :iteration
24 26
 
25 27
   # Who maintains this package? This could be the upstream author
@@ -40,6 +42,7 @@ class FPM::Package
40 42
   attr_accessor :license
41 43
 
42 44
   # A identifier representing the vendor. Any string is fine.
  45
+  # This is usually who produced the software.
43 46
   attr_accessor :vendor
44 47
 
45 48
   # What architecture is this package for?
@@ -69,121 +72,110 @@ class FPM::Package
69 72
   # Array of configuration files
70 73
   attr_accessor :config_files
71 74
 
72  
-  # Package path prefix
73  
-  attr_accessor :prefix
  75
+  # Any other attributes specific to this package.
  76
+  # This is where you'd put rpm, deb, or other specific attributes.
  77
+  attr_accessor :attributes
74 78
 
75  
-	# target-specific settings
76  
-	attr_accessor :settings
  79
+  private
77 80
 
78  
-  def initialize(source, params={})
79  
-    @source = source
  81
+  def initialize
80 82
     @logger = Logger.new(STDERR)
81 83
     @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
82 84
 
83  
-    @name = source[:name] # || fail
84  
-
85 85
     # Default version is 1.0 in case nobody told us a specific version.
86  
-    @version = source[:version] || "1.0"
87  
-    @epoch = source[:epoch]
88  
-
89  
-    @dependencies = source[:dependencies] || []
90  
-    # Iteration can be nil. If nil, the fpm package implementation is expected
91  
-    # to handle any default value that should be instead.
92  
-    @iteration = source[:iteration]
93  
-    @url = source[:url] || "http://nourlgiven.example.com/no/url/given"
94  
-    @category = source[:category] || "default"
95  
-    @license = source[:license] || "unknown"
96  
-    @vendor = source[:vendor] || "none"
97  
-    #@maintainer = source[:maintainer] || "<#{ENV["USER"]}@#{Socket.gethostname}>"
98  
-    @maintainer = source[:maintainer]
99  
-
100  
-    # Default maintainer if none given.
101  
-    if @maintainer.nil? or @maintainer.empty?
102  
-      # Reference
103  
-      # http://www.debian.org/doc/manuals/maint-guide/first.en.html
104  
-      # http://wiki.debian.org/DeveloperConfiguration
105  
-      # https://github.com/jordansissel/fpm/issues/37
106  
-      if ENV.include?("DEBEMAIL") and ENV.include?("DEBFULLNAME")
107  
-        # Use DEBEMAIL and DEBFULLNAME as the default maintainer if available.
108  
-        @maintainer = "#{ENV["DEBFULLNAME"]} <#{ENV["DEBEMAIL"]}>"
109  
-      else
110  
-        # TODO(sissel): Maybe support using 'git config' for a default as well?
111  
-        # git config --get user.name, etc can be useful.
112  
-        #
113  
-        # Otherwise default to user@currenthost
114  
-        @maintainer = "<#{ENV["USER"]}@#{Socket.gethostname}>"
115  
-      end
  86
+    @version = 1.0
  87
+    @epoch = 1
  88
+    @dependencies = []
  89
+    @iteration = nil
  90
+    @url = nil
  91
+    @category = "default"
  92
+    @license = "unknown"
  93
+    @vendor = "none"
  94
+
  95
+    # Attributes for this specific package 
  96
+    @attributes = {}
  97
+
  98
+    # Reference
  99
+    # http://www.debian.org/doc/manuals/maint-guide/first.en.html
  100
+    # http://wiki.debian.org/DeveloperConfiguration
  101
+    # https://github.com/jordansissel/fpm/issues/37
  102
+    if ENV.include?("DEBEMAIL") and ENV.include?("DEBFULLNAME")
  103
+      # Use DEBEMAIL and DEBFULLNAME as the default maintainer if available.
  104
+      @maintainer = "#{ENV["DEBFULLNAME"]} <#{ENV["DEBEMAIL"]}>"
  105
+    else
  106
+      # TODO(sissel): Maybe support using 'git config' for a default as well?
  107
+      # git config --get user.name, etc can be useful.
  108
+      #
  109
+      # Otherwise default to user@currenthost
  110
+      @maintainer = "<#{ENV["USER"]}@#{Socket.gethostname}>"
116 111
     end
117 112
 
118 113
     # If @architecture is nil, the target package should provide a default.
119 114
     # Special 'architecture' values include "all" (aka rpm's noarch, debian's all)
120 115
     # Another special includes "native" which will be the current platform's arch.
121  
-    @architecture = source[:architecture]
122  
-    @description = source[:description] || "no description given"
123  
-    @provides = source[:provides] || []
124  
-    @replaces = source[:replaces] || []
125  
-    @conflicts = source[:conflicts] || []
126  
-    @scripts = source[:scripts]
127  
-    @config_files = source[:config_files] || []
128  
-    @prefix = source[:prefix] || "/"
129  
-
130  
-    # Target-specific settings, mirrors :settings metadata in FPM::Source
131  
-    @settings = params[:settings] || {}
  116
+    @architecture = "all"
  117
+    @description = "no description given"
  118
+
  119
+    # TODO(sissel): Implement provides, requires, conflicts, etc later.
  120
+    #@provides = []
  121
+    #@conflicts = source[:conflicts] || []
  122
+    #@scripts = source[:scripts]
  123
+    #@config_files = source[:config_files] || []
  124
+    #@prefix = source[:prefix] || "/"
132 125
   end # def initialize
133 126
 
134  
-  # nobody needs md5sums by default.
135  
-  def needs_md5sums
136  
-    false
137  
-  end # def needs_md5sums
  127
+  # Add a new source to this package.
  128
+  # The exact behavior depends on the kind of package being managed.
  129
+  #
  130
+  # For instance: 
  131
+  #
  132
+  # * for FPM::Package::Dir, << expects a path to a directory or files.
  133
+  # * for FPM::Package::RPM, << expects a path to an rpm.
  134
+  #
  135
+  # The idea is that you can keep pumping in new things to a package
  136
+  # for later conversion or output.
  137
+  #
  138
+  # Implementations are expected to put files relevant to the 'input' in the
  139
+  # staging_path
  140
+  def <<(input)
  141
+    raise NotImplementedError.new
  142
+  end # def <<
138 143
 
139 144
   # TODO [Jay]: make this better...?
140 145
   def type
141 146
     self.class.name.split(':').last.downcase
142 147
   end # def type
143 148
 
144  
-  def template(path=nil)
145  
-    path ||= "#{type}.erb"
146  
-    @logger.info("Reading template: #{path}")
147  
-    tpl = File.read("#{FPM::DIRS[:templates]}/#{path}")
148  
-    return ERB.new(tpl, nil, "-")
149  
-  end # def template
150  
-
151  
-  def render_spec
152  
-    # find all files in paths given.
153  
-    paths = []
154  
-    @source.paths.each do |path|
155  
-      Find.find(path) { |p| paths << p }
156  
-    end
157  
-    #@logger.info(:paths => paths.sort)
158  
-    template.result(binding)
159  
-  end # def render_spec
160  
-
161  
-  # Default specfile generator just makes one specfile, whatever that is for
162  
-  # this package.
163  
-  def generate_specfile(builddir)
164  
-    File.open(specfile(builddir), "w") do |f|
165  
-      f.puts render_spec
  149
+  # Convert this package to a new package type
  150
+  def convert(klass)
  151
+    pkg = klass.new
  152
+    pkg.instance_variable_set(:@staging_path, staging_path)
  153
+
  154
+    # copy other bits
  155
+    ivars = [
  156
+      :architecture, :attributes, :category, :config_files, :conflicts,
  157
+      :dependencies, :description, :epoch, :iteration, :license, :maintainer,
  158
+      :name, :provides, :replaces, :scripts, :url, :vendor, :version
  159
+    ]
  160
+    ivars.each do |ivar|
  161
+      pkg.instance_variable_set(ivar, instance_variable_get(ivar))
166 162
     end
167  
-  end # def generate_specfile
168 163
 
169  
-  def default_output
170  
-    if iteration
171  
-      "#{name}-#{version}-#{iteration}.#{architecture}.#{type}"
172  
-    else
173  
-      "#{name}-#{version}.#{architecture}.#{type}"
174  
-    end
175  
-  end # def default_output
  164
+    return pkg
  165
+  end # def convert
176 166
 
177  
-  def fixpath(path)
178  
-    if path[0,1] != "/"
179  
-      path = File.join(@source.root, path)
180  
-    end
181  
-    return path if File.symlink?(path)
182  
-    @logger.info(:fixpath => path)
183  
-    realpath = Pathname.new(path).realpath.to_s
184  
-    re = Regexp.new("^#{Regexp.escape(@source.root)}")
185  
-    realpath.gsub!(re, "")
186  
-    @logger.info(:fixpath_result => realpath)
187  
-    return realpath
188  
-  end # def fixpath
  167
+  def output(path)
  168
+    raise NotImplementedError.new("This must be implemented by FPM::Package subclasses")
  169
+  end # def output
  170
+
  171
+  def staging_path
  172
+    @staging_path ||= ::Dir.mktmpdir(File.join(::Dir.pwd, "package-#{type}-staging"))
  173
+  end # def staging_path
  174
+
  175
+  # Clean up any temporary storage used by this class.
  176
+  def cleanup
  177
+    FileUtils.rm_r(staging_path)
  178
+  end # def cleanup
  179
+
  180
+  public(:type, :initialize, :convert, :output, :<<, :cleanup, :staging_path)
189 181
 end # class FPM::Package
77  lib/fpm/package/dir.rb
... ...
@@ -0,0 +1,77 @@
  1
+require "fpm/package"
  2
+require "backports"
  3
+require "fileutils"
  4
+require "find"
  5
+
  6
+class FPM::Package::Dir < FPM::Package
  7
+  private
  8
+
  9
+  def <<(path)
  10
+    @paths ||= []
  11
+    @paths << path
  12
+
  13
+    clone(path, staging_path)
  14
+  end # def <<
  15
+
  16
+  def output(dir)
  17
+    dir = File.expand_path(dir)
  18
+    @paths.each do |path|
  19
+      ::Dir.chdir(staging_path) do
  20
+        clone(path, dir)
  21
+      end
  22
+    end
  23
+  end
  24
+
  25
+  private
  26
+  # Copy a file or directory to a destination
  27
+  #
  28
+  # This is special because it respects the full path of the source.
  29
+  # Aditionally, hardlinks will be used instead of copies.
  30
+  #
  31
+  # Example:
  32
+  #
  33
+  #     clone("/tmp/hello/world", "/tmp/example")
  34
+  #
  35
+  # The above will copy, recursively, /tmp/hello/world into
  36
+  # /tmp/example/hello/world
  37
+  def clone(source, destination)
  38
+    # Copy all files from 'path' into staging_path
  39
+
  40
+    ::Dir.chdir(@attributes[:chdir] || ".") do
  41
+      p :chdir => ::Dir.pwd, :source => source
  42
+      Find.find(source).each do |file|
  43
+        next if source == file # ignore the directory itself
  44
+        # Translate file paths with attributes like 'prefix' and 'chdir'
  45
+        if @attributes[:prefix]
  46
+          target = File.join(destination, @attributes[:prefix], file)
  47
+        else
  48
+          target = File.join(destination, file)
  49
+        end
  50
+
  51
+        copy(file, target)
  52
+      end
  53
+    end
  54
+  end # def clone
  55
+
  56
+  def copy(source, destination)
  57
+    directory = File.dirname(destination)
  58
+    if !File.directory?(directory)
  59
+      FileUtils.mkdir_p(directory)
  60
+    end
  61
+
  62
+    # Create a directory if this path is a directory
  63
+    if File.directory?(source)
  64
+      FileUtils.mkdir(destination)
  65
+    else
  66
+      # Otherwise try copying the file.
  67
+      begin
  68
+        File.link(source, destination)
  69
+      rescue Errno::EXDEV
  70
+        # Hardlink attempt failed, copy it instead
  71
+        FileUtils.copy(source, destination)
  72
+      end
  73
+    end
  74
+  end # def copy
  75
+
  76
+  public(:<<, :output)
  77
+end # class FPM::Package::Dir
124  lib/fpm/source.rb
@@ -21,126 +21,16 @@ class FPM::Source
21 21
     define_method(:"#{attr}=") { |v| self[attr] = v}
22 22
   end
23 23
 
24  
-  def dependencies
25  
-    self[:dependencies] ||= []
26  
-  end
27  
-
28  
-  attr_reader :paths
29  
-  attr_accessor :root
30  
-
31  
-  def initialize(paths, root, params={})
  24
+  def initialize
32 25
     @logger = Logger.new(STDERR)
33 26
     @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
34  
-
35  
-    @paths = paths
36  
-    @root = root
37  
-
38  
-    self[:suffix] = params[:suffix]
39  
-    self[:settings] = params[:settings]
40  
-
41  
-    get_source(params)
42  
-    get_metadata
43  
-
44  
-    # override the inferred data with the passed-in data
45  
-    params.each do |k,v|
46  
-      self[k] = v if v != nil
47  
-    end
48 27
   end # def initialize
49 28
 
50  
-  # this method should take the paths and root and infer as much
51  
-  # about the package as it can.
52  
-  def get_metadata
53  
-    raise NoMethodError,
54  
-      "Please subclass FPM::Source and define get_metadata"
55  
-  end # def get_metadata
56  
-
57  
-  # This method should be overridden by package sources that need to do any
58  
-  # kind of fetching.
59  
-  def get_source(params)
60  
-    # noop by default
61  
-  end # def get_source
62  
-
63  
-  def make_tarball!(tar_path, builddir)
64  
-    raise NoMethodError,
65  
-      "Please subclass FPM::Source and define make_tarball!(tar_path)"
66  
-  end
67  
-
68  
-  def metadata
69  
-    @metadata ||= {}
70  
-  end
71  
-
72  
-  def [](key)
73  
-    metadata[key.to_sym]
74  
-  end
75  
-
76  
-  def []=(key,val)
77  
-    metadata[key.to_sym] = val
78  
-  end
79  
-
80  
-  # MySourceClass.new('/tmp/build').package(FPM::Deb).assemble(params)
81  
-  def package(pkg_cls)
82  
-    pkg_cls.new(self)
83  
-  end
84  
-
85  
-  private
86  
-  def tar(output, paths, chdir=".")
87  
-    dirs = []
88  
-
89  
-    # Include all directory entries at the top of the tarball
90  
-    paths = [ paths ] if paths.is_a? String
91  
-    paths.each do |path|
92  
-      while path != "/" and path != "."
93  
-        dirs << path if !dirs.include?(path)
94  
-        path = File.dirname(path)
95  
-      end
96  
-    end # paths.each
97  
-
98  
-    # Want directories to be sorted thusly: [ "/usr", "/usr/bin" ]
99  
-    # Why? tar and some package managers sometimes fail if the tar is created
100  
-    # like: [ "/opt/fizz", "/opt" ]
101  
-    # dpkg -i will fail if /opt doesn't exist, sorting it by length ensures
102  
-    # /opt is created before /opt/fizz.
103  
-    dirs.sort! { |a,b| a.size <=> b.size }
104  
-    paths.sort! { |a,b| a.size <=> b.size }
105  
-
106  
-
107  
-    # Solaris's tar is pretty neutered, so implement --exclude and such
108  
-    # ourselves.
109  
-    # TODO(sissel): May need to implement our own tar file generator
110  
-    # so we can enforce file ownership. Again, solaris' tar doesn't support
111  
-    # --owner, etc.
112  
-    #paths = []
113  
-    #dirs.each do |dir|
114  
-      #Dir.glob(File.join(dir, "**", "*")).each do |path|
115  
-        #next if excludesFile.fnmatch?(
116  
-      #end
117  
-    #end
118  
-
119  
-    excludes = self[:exclude].map { |e| ["--exclude", e] }.flatten
120  
-
121  
-    # TODO(sissel): To properly implement excludes as regexps, we
122  
-    # will need to find files ourselves. That may be more work
123  
-    # than it is worth. For now, rely on tar's --exclude.
124  
-    dir_tar = [tar_cmd, "--owner=0", "--group=0" ] \
125  
-              + excludes \
126  
-              + ["-cf", output, "--no-recursion" ]
127  
-
128  
-    # Only if directories and paths do not have duplicates ...
129  
-    dirs -= paths
130  
-
131  
-    if dirs.any?
132  
-      ::Dir.chdir(chdir) do
133  
-        safesystem *(dir_tar += dirs)
134  
-      end
135  
-    end
136  
-
137  
-    files_tar = [ tar_cmd ] \
138  
-                + excludes \
139  
-                + [ "--owner=0", "--group=0", "-rf", output ] \
140  
-                + paths
141  
-    ::Dir.chdir(chdir) do
142  
-      safesystem(*files_tar)
143  
-    end
144  
-  end # def tar
  29
+  # Add a new argument to this source
  30
+  # The effect of this is specific to the source's implementation,
  31
+  # but in general this means you are adding something to this source.
  32
+  def <<(arg)
  33
+    raise NotImplementedError.new
  34
+  end # def <<
145 35
 
146 36
 end # class FPM::Source
11  test/Makefile
... ...
@@ -1,11 +0,0 @@
1  
-TESTS=$(shell git ls-files '*.test')
2  
-
3  
-.PHONY: test
4  
-test: $(TESTS)
5  
-
6  
-.PHONY: $(TESTS)
7  
-$(TESTS):
8  
-	@bash test.sh $@
9  
-
10  
-clean:
11  
-	rm *.deb *.rpm *.gem
24  test/all.rb
... ...
@@ -0,0 +1,24 @@
  1
+require "rubygems"
  2
+require "minitest/spec"
  3
+require "minitest/autorun"
  4
+
  5
+# Get coverage report
  6
+require "simplecov"
  7
+SimpleCov.start
  8
+
  9
+# Add '../lib' to the require path.
  10
+$: << File.join(File.dirname(__FILE__), "..", "lib")
  11
+
  12
+def use(path)
  13
+  puts "Loading tests from #{path}"
  14
+  require File.expand_path(path)
  15
+end
  16
+
  17
+dirname = File.dirname(__FILE__)
  18
+use File.join(dirname, "docs.rb")
  19
+
  20
+# Load tests from ./*/**/*.rb (usually ./libraryname/....)
  21
+glob = File.join(dirname, "*", "**", "*.rb")
  22
+Dir.glob(glob).each do |path|
  23
+  use path
  24
+end
2  test/dir-deb-with-debconf.out
... ...
@@ -1,2 +0,0 @@
1  
-       0 bytes,     0 lines   *  config               
2  
-       0 bytes,     0 lines      templates            
17  test/dir-deb-with-debconf.test
... ...
@@ -1,17 +0,0 @@
1  
-#!/bin/bash
2  
-
3  
-run() {
4  
-  mkdir -p $tmpdir/prefix
5  
-  touch $tmpdir/config
6  
-  touch $tmpdir/templates
7  
-
8  
-  fpm -s dir -t deb -n testing -a all \
9  
-  --deb-config $tmpdir/config \
10  
-  --deb-templates $tmpdir/templates \
11  
-  $tmpdir/prefix
12  
-
13  
-  file=testing_1.0_all.deb
14  
-  dpkg -I $file | grep "\(config\)\|\(templates\)" > $output
15  
-
16  
-  rm $file
17  
-}
19  test/dir-deb-with-prefix.out
... ...
@@ -1,19 +0,0 @@
1  
-./
2  
-./opt/
3  
-./opt/foo/
4  
-./opt/foo/bar/
5  
-./opt/foo/bar/a/
6  
-./opt/foo/bar/a/d/
7  
-./opt/foo/bar/a/d/hello
8  
-./opt/foo/bar/a/e/
9  
-./opt/foo/bar/a/f/
10  
-./opt/foo/bar/a/hello
11  
-./opt/foo/bar/b/
12  
-./opt/foo/bar/b/d/
13  
-./opt/foo/bar/b/e/
14  
-./opt/foo/bar/b/f/
15  
-./opt/foo/bar/c/
16  
-./opt/foo/bar/c/d/
17  
-./opt/foo/bar/c/d/hello
18  
-./opt/foo/bar/c/e/
19  
-./opt/foo/bar/c/f/
17  test/dir-deb-with-prefix.test
... ...
@@ -1,17 +0,0 @@
1  
-#!/bin/bash
2  
-
3  
-run() {
4  
-  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
5  
-  touch $tmpdir/a/hello
6  
-  touch $tmpdir/a/d/hello
7  
-  touch $tmpdir/c/d/hello
8  
-
9  
-  prefix=/opt/foo/bar
10  
-
11  
-  fpm -s dir -t deb -n testing -a all --prefix $prefix -C $tmpdir 
12  
-
13  
-  file=testing_1.0_all.deb
14  
-  dpkg -c $file | awk '{$1=$2=$3=$4=$5="";print}' | sed -e 's/^ *//' | sort > $output
15  
-
16  
-  rm $file
17  
-}
17  test/dir-deb.out.template
... ...
@@ -1,17 +0,0 @@
1  
-tmp/
2  
-tmp/TMPDIR/
3  
-tmp/TMPDIR/a/
4  
-tmp/TMPDIR/a/d/
5  
-tmp/TMPDIR/a/d/hello
6  
-tmp/TMPDIR/a/e/
7  
-tmp/TMPDIR/a/f/
8  
-tmp/TMPDIR/a/hello
9  
-tmp/TMPDIR/b/
10  
-tmp/TMPDIR/b/d/
11  
-tmp/TMPDIR/b/e/
12  
-tmp/TMPDIR/b/f/
13  
-tmp/TMPDIR/c/
14  
-tmp/TMPDIR/c/d/
15  
-tmp/TMPDIR/c/d/hello
16  
-tmp/TMPDIR/c/e/
17  
-tmp/TMPDIR/c/f/
23  test/dir-deb.test
... ...
@@ -1,23 +0,0 @@
1  
-#!/bin/bash
2  
-
3  
-run() {
4  
-  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
5  
-  touch $tmpdir/a/hello
6  
-  touch $tmpdir/a/d/hello
7  
-  touch $tmpdir/c/d/hello
8  
-
9  
-  prefix=/opt/foo/bar
10  
-
11  
-  fpm -s dir -t deb -n testing -a all $tmpdir
12  
-
13  
-  file=testing_1.0_all.deb
14  
-  dpkg -c $file | awk '{$1=$2=$3=$4=$5="";print}' | sed -e 's/^ *//' | sort > $output
15  
-  #ar p $file data.tar.gz | tar -ztf - | sort > $output
16  
-  sed -e "s,TMPDIR,$(basename $tmpdir)," $expected.template > $expected
17  
-
18  
-  rm $file
19  
-}
20  
-
21  
-clean() {
22  
-  rm $expected
23  
-}
16  test/dir-rpm-with-prefix.out
... ...
@@ -1,16 +0,0 @@
1  
-/opt/foo/bar
2  
-/opt/foo/bar/a
3  
-/opt/foo/bar/a/d
4  
-/opt/foo/bar/a/d/hello
5  
-/opt/foo/bar/a/e
6  
-/opt/foo/bar/a/f
7  
-/opt/foo/bar/a/hello
8  
-/opt/foo/bar/b
9  
-/opt/foo/bar/b/d
10  
-/opt/foo/bar/b/e
11  
-/opt/foo/bar/b/f
12  
-/opt/foo/bar/c
13  
-/opt/foo/bar/c/d
14  
-/opt/foo/bar/c/d/hello
15  
-/opt/foo/bar/c/e
16  
-/opt/foo/bar/c/f
15  test/dir-rpm-with-prefix.test
... ...
@@ -1,15 +0,0 @@
1  
-#!/bin/bash
2  
-
3  
-run() {
4  
-  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
5  
-  touch $tmpdir/a/hello
6  
-  touch $tmpdir/a/d/hello
7  
-  touch $tmpdir/c/d/hello
8  
-
9  
-  prefix=/opt/foo/bar
10  
-
11  
-  fpm -s dir -t rpm -n testing -a all --prefix $prefix -C $tmpdir 
12  
-
13  
-  rpm -qlp testing-1.0-1.noarch.rpm > $output
14  
-  rm testing-1.0-1.noarch.rpm
15  
-}
16  test/dir-rpm.out.template
... ...
@@ -1,16 +0,0 @@
1  
-/tmp/TMPDIR
2  
-/tmp/TMPDIR/a
3  
-/tmp/TMPDIR/a/d
4  
-/tmp/TMPDIR/a/d/hello
5  
-/tmp/TMPDIR/a/e
6  
-/tmp/TMPDIR/a/f
7  
-/tmp/TMPDIR/a/hello
8  
-/tmp/TMPDIR/b
9  
-/tmp/TMPDIR/b/d
10  
-/tmp/TMPDIR/b/e
11  
-/tmp/TMPDIR/b/f
12  
-/tmp/TMPDIR/c
13  
-/tmp/TMPDIR/c/d
14  
-/tmp/TMPDIR/c/d/hello
15  
-/tmp/TMPDIR/c/e
16  
-/tmp/TMPDIR/c/f
20  test/dir-rpm.test
... ...
@@ -1,20 +0,0 @@
1  
-#!/bin/bash
2  
-
3  
-run() {
4  
-  mkdir -p $tmpdir/{a,b,c}/{d,e,f}
5  
-  touch $tmpdir/a/hello
6  
-  touch $tmpdir/a/d/hello
7  
-  touch $tmpdir/c/d/hello
8  
-
9  
-  fpm -s dir -t rpm -n testing -a all $tmpdir
10  
-
11  
-  file=testing-1.0-1.noarch.rpm
12  
-  rpm -qlp $file > $output
13  
-  sed -e "s,TMPDIR,$(basename $tmpdir)," $expected.template > $expected
14  
-
15  
-  rm $file
16  
-}
17  
-
18  
-clean() {
19  
-  rm $expected
20  
-}
41  test/docs.rb
... ...
@@ -0,0 +1,41 @@
  1
+require "rubygems"                                                                                               
  2
+require "yard"                                                                                                   
  3
+require File.join(File.expand_path(File.dirname(__FILE__)), "testing")
  4
+require "minitest/autorun"
  5
+
  6
+describe "documentation tests" do
  7
+  before do
  8
+    # Use YARD to parse all ruby files found in '../lib'
  9
+    libdir = File.join(File.dirname(__FILE__), "..", "lib")
  10
+    YARD::Registry.load(Dir.glob(File.join(libdir, "**", "*.rb")))
  11
+    @registry = YARD::Registry.all
  12
+  end
  13
+
  14
+  test "All classes, methods, modules, and constants must be documented" do
  15
+    # Note, the 'find the undocumented things' code here is 
  16
+    # copied mostly from: YARD 0.7.5's lib/yard/cli/stats.rb
  17
+    #
  18
+    # Find all undocumented classes, modules, and constants
  19
+    undocumented = @registry.select do |o| 
  20
+      [:class, :module, :constant].include?(o.type) && o.docstring.blank?
  21
+    end
  22
+
  23
+    # Find all undocumented methods
  24
+    methods = @registry.select { |m| m.type == :method }
  25
+    methods.reject! { |m| m.is_alias? || !m.is_explicit? }
  26
+    undocumented += methods.select do |m| 
  27
+      m.docstring.blank? && !m.overridden_method
  28
+    end
  29
+
  30
+    if (undocumented.length > 0)
  31
+      message = ["The following are not documented"]
  32
+      undocumented.each do |o|
  33
+        message << "* #{o.type.to_s} #{o.to_s} <#{o.file}:#{o.line}>"
  34
+      end
  35
+
  36
+      flunk(message.join("\n"))
  37
+    else
  38
+      pass
  39
+    end
  40
+  end
  41
+end
89  test/fpm/package/dir.rb
... ...
@@ -0,0 +1,89 @@
  1
+require "rubygems"
  2
+require File.join(File.dirname(File.expand_path(__FILE__)), "..", "..", "testing")
  3
+$: << File.join(File.dirname(File.expand_path(__FILE__)), "..", "..", "..", "lib")
  4
+require "minitest/autorun"
  5
+require "tmpdir"
  6
+require "fileutils"
  7
+require "fpm/package/dir"
  8
+require "rush" # for simple file stuff
  9
+
  10
+describe FPM::Package::Dir do
  11
+  before do
  12
+    @source = FPM::Package::Dir.new
  13
+    @rush = Rush::Box.new("localhost")
  14
+    @tmpdir = @rush[::Dir.mktmpdir("package-test-tmpdir")]
  15
+    @output = @rush[::Dir.mktmpdir("package-test-output")]
  16
+  end # before
  17
+
  18
+  after do
  19
+    @source.cleanup
  20
+    FileUtils.rm_r(@tmpdir.full_path)
  21
+    FileUtils.rm_r(@output.full_path)
  22
+  end # after
  23
+
  24
+  test "adding a single file" do
  25
+    file = @tmpdir["hello"]
  26
+    file.write "Hello world"
  27
+    @source << @tmpdir.full_path
  28
+
  29
+    @source.output(@output.full_path)
  30
+    assert_equal(@output[File.join(".", file.full_path)].contents,
  31
+                 file.contents, "The file #{@tmpdir["hello"].full_path} should appear in the output")
  32
+  end
  33
+
  34
+  test "single file in a directory" do
  35
+    dir = @tmpdir.create_dir("a/b/c")
  36
+    file = dir.create_file("hello")
  37
+    file.write "Hello world"
  38
+    @source << @tmpdir.full_path
  39
+
  40
+    @source.output(@output.full_path)
  41
+    assert_equal(@output[File.join(".", file.full_path)].contents,
  42
+                 file.contents, "The file #{@tmpdir["a/b/c/hello"].full_path} should appear in the output")
  43
+  end
  44
+
  45
+  test "multiple files" do
  46
+    dir = @tmpdir.create_dir("a/b/c")
  47
+    files = rand(50).times.collect do |i|
  48
+      dir.create_file("hello-#{i}")
  49
+    end
  50
+    files.each { |f| f.write(rand(1000)) }
  51
+
  52
+    @source << @tmpdir.full_path
  53
+    @source.output(@output.full_path)
  54
+
  55
+    files.each do |file|
  56
+      assert_equal(@output[File.join(".", file.full_path)].contents,
  57
+                   file.contents, "The file #{file.full_path} should appear in the output")
  58
+    end
  59
+  end
  60
+
  61
+  test "single file with prefix" do
  62
+    prefix = @source.attributes[:prefix] = "/usr/local"
  63
+    file = @tmpdir["hello"]
  64
+    file.write "Hello world"
  65
+    @source << @tmpdir.full_path
  66
+
  67
+    @source.output(@output.full_path)
  68
+
  69
+    expected_path = File.join(".", prefix, file.full_path)
  70
+    assert_equal(@output[expected_path].contents,
  71
+                 file.contents, "The file #{@tmpdir["hello"].full_path} should appear in the output")
  72
+  end
  73
+
  74
+  test "single file with prefix and chdir" do
  75
+    prefix = @source.attributes[:prefix] = "/usr/local"
  76
+    chdir = @source.attributes[:chdir] = @tmpdir.full_path
  77
+    file = @tmpdir["hello"]
  78
+    file.write "Hello world"
  79
+    @source << "." # since we chdir, copy the entire root
  80
+
  81
+    @source.output(@output.full_path)
  82
+
  83
+    # path relative to the @output directory.
  84
+    expected_path = File.join(".", prefix, file.name)
  85
+    assert_equal(@output[expected_path].contents,
  86
+                 file.contents, "The file #{@tmpdir["hello"].full_path} should appear in the output")
  87
+  end
  88
+
  89
+end # describe FPM::Package::Dir
16  test/gem-deb.out
... ...
@@ -1,16 +0,0 @@
1  
-./usr/
2  
-./usr/lib/
3  
-./usr/lib/ruby/
4  
-./usr/lib/ruby/gems/
5  
-./usr/lib/ruby/gems/1.8/
6  
-./usr/lib/ruby/gems/1.8/bin/
7  
-./usr/lib/ruby/gems/1.8/bin/rails
8  
-./usr/lib/ruby/gems/1.8/cache/
9  
-./usr/lib/ruby/gems/1.8/cache/rails-3.1.0.gem
10  
-./usr/lib/ruby/gems/1.8/doc/
11  
-./usr/lib/ruby/gems/1.8/gems/
12  
-./usr/lib/ruby/gems/1.8/gems/rails-3.1.0/
13  
-./usr/lib/ruby/gems/1.8/gems/rails-3.1.0/bin/
14  
-./usr/lib/ruby/gems/1.8/gems/rails-3.1.0/bin/rails
15  
-./usr/lib/ruby/gems/1.8/specifications/
16  
-./usr/lib/ruby/gems/1.8/specifications/rails-3.1.0.gemspec
17  test/gem-deb.test
... ...
@@ -1,17 +0,0 @@
1  
-#!/bin/bash
2  
-RAILS_VERSION=3.1.0
3  
-
4  
-run() {
5  
-  # Force the gem installation path to match the one of the expected output
6  
-  export GEM_HOME=/usr/lib/ruby/gems/1.8
7  
-  
8  
-  fpm -s gem -t deb -v $RAILS_VERSION rails
9  
-
10  
-  file=rubygem-rails_${RAILS_VERSION}_all.deb
11  
-  dpkg -c $file | awk '{$1=$2=$3=$4=$5="";print}' | sed -e 's/^ *//' | sort > $output
12  
-  rm $file
13  
-}
14  
-
15  
-clean() {
16  
-  rm rails-${RAILS_VERSION}.gem
17  
-}
14  test/testing.rb
... ...
@@ -0,0 +1,14 @@
  1
+require "rubygems"
  2
+require "minitest/spec"
  3
+
  4
+# Add '../lib' to the require path.
  5
+$: << File.join(File.dirname(__FILE__), "..", "lib")
  6
+
  7
+# I don't really like monkeypatching, but whatever, this is probably better
  8
+# than overriding the 'describe' method.
  9
+class MiniTest::Spec
  10
+  class << self
  11
+    # 'it' sounds wrong, call it 'test'
  12
+    alias :test :it
  13
+  end
  14
+end

0 notes on commit f7187f1

Please sign in to comment.
Something went wrong with that request. Please try again.