purplepkg 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/bin/install_ruby ADDED
@@ -0,0 +1,49 @@
1
+ #!/bin/bash
2
+
3
+ if [ -z "$1" ]; then
4
+ echo "Usage: $0 ruby-<version>.tar.gz"
5
+ exit 1
6
+ fi
7
+
8
+ if [ ! -f "$1" ]; then
9
+ echo "File does not exist: $1"
10
+ exit 1
11
+ fi
12
+
13
+ if [ ! -f 'purple.gemspec' ]; then
14
+ echo "Please only run this script from purple source directory."
15
+ exit 1
16
+ fi
17
+
18
+ rm -f install_ruby.log
19
+ export TARBALL=$1
20
+ export PURPLE_TOPDIR=`pwd`
21
+
22
+ function system() {
23
+ echo -n "$1" >&2
24
+ shift
25
+ $* >> $PURPLE_TOPDIR/install_ruby.log 2>&1
26
+ STATUS=$?
27
+ echo >&2
28
+ if [ 0 -ne $STATUS ]; then
29
+ echo "Error ocurred. Please check install_ruby.log."
30
+ fi
31
+ }
32
+
33
+ # Determine ruby topdir
34
+ export RUBY_TOPDIR=/tmp/`tar tzf "$TARBALL" | head -1`
35
+
36
+ # Extract source
37
+ system "Extracting source..." tar -C /tmp xzf $TARBALL
38
+
39
+ cd $RUBY_TOPDIR
40
+
41
+ # Compile ruby
42
+ system "Configuring..." ./configure
43
+ system "Building..." make
44
+
45
+ # Run purple to stage ruby package
46
+ $RUBY_TOPDIR/miniruby -I lib -I "$RUBY_TOPDIR"/lib bin/purple -i $TARBALL
47
+
48
+ # Clean /tmp
49
+ rm -fr "$RUBY_TOPDIR"
data/bin/purple ADDED
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'uri'
4
+ require 'uri/http'
5
+ require 'getoptlong'
6
+
7
+ require 'purple'
8
+
9
+ def usage
10
+ puts <<-EOS
11
+ Purple Packager, Copyright (c) 2004, Simon Conrad-Armes <curne@curnomatic.dk>
12
+ Rights granted, under GNU GPL (version 2 or later), see file LICENSE
13
+
14
+ Usage: #{File.basename $0} [options] <package>
15
+
16
+ Options:
17
+ --make Make a package from the staged install.
18
+ -m
19
+ --deploy Deploy the built package. Implies --make.
20
+ -i
21
+ --skip-to=step Skip to the given step [prepare].
22
+ --stop-at=step Stop after given step is complete [build].
23
+ --manual Print the manual page for Purple Package.
24
+
25
+ The arguments given to --skip-to and --stop-at must be one of
26
+ 'prepare', 'build', 'stage', or 'deps'.
27
+
28
+ <package>
29
+ The package argument may be a url or path to a local file path. The file
30
+ ending determines how it is handled:
31
+ .tar.gz Source Tarball assumed. A purple spec is created
32
+ inferring the name and version from the filename.
33
+ .purple Purple spec script. Contains references to source and
34
+ build instructions.
35
+ .purple-src Purple source package. Contains source files and build
36
+ instructions.
37
+ .purple-bin Purple binary package.
38
+
39
+ EOS
40
+ exit 1
41
+ end
42
+
43
+ def filetype url
44
+ filename = File.basename(URI.parse(url).path)
45
+ return case filename
46
+ when /\.tar\.(gz|bz2)|\.tgz$/
47
+ :tarball
48
+ when /\.purple$/
49
+ :script
50
+ end
51
+ end
52
+
53
+ ALL_STEPS = { :prepare => 0, :build => 2, :stage => 4, :deps => 6 }
54
+
55
+
56
+ usage if 0 == ARGV.size
57
+
58
+ opts = GetoptLong.new
59
+ opts.set_options(
60
+ [ '--help', GetoptLong::OPTIONAL_ARGUMENT],
61
+ [ '--make', '-m', GetoptLong::NO_ARGUMENT],
62
+ [ '--deploy', '-i', GetoptLong::NO_ARGUMENT],
63
+ [ '--skip-to', GetoptLong::REQUIRED_ARGUMENT],
64
+ [ '--stop-at', GetoptLong::REQUIRED_ARGUMENT],
65
+ [ '--manual', GetoptLong::REQUIRED_ARGUMENT]
66
+ )
67
+
68
+ OPTIONS = Hash.new
69
+ opts.each_option { |name,arg| OPTIONS[name.gsub(/^--/, '')] = arg }
70
+ p OPTIONS
71
+
72
+ usage if OPTIONS.has_key? 'help'
73
+
74
+ steps = [:prepare, :config, :build, :stage]
75
+
76
+ if OPTIONS.has_key? 'make' or 'deps' == OPTIONS['stop-at']
77
+ steps << :deps
78
+ end
79
+
80
+ if OPTIONS.has_key? 'skip-to'
81
+ if 'make' == OPTIONS['skip-to']
82
+ first = steps.size
83
+ else
84
+ first = steps.index OPTIONS['skip-to'].intern
85
+ end
86
+ else
87
+ first = 0
88
+ end
89
+
90
+ if OPTIONS.has_key? 'stop-at'
91
+ last = steps.index OPTIONS['stop-at'].intern
92
+ else
93
+ last = steps.size - 1
94
+ end
95
+
96
+ steps = steps[first..last]
97
+
98
+
99
+ # Convert local paths to urls
100
+ arg_ref = ARGV[0]
101
+ arg_uri = URI.parse(arg_ref)
102
+ if not arg_uri.scheme
103
+ arg_uri.scheme = 'file'
104
+ arg_uri.path = File.join(Dir.pwd, arg_uri.path) if arg_uri.path !~ %r"^/"
105
+ end
106
+ arg_ref = arg_uri.to_s
107
+
108
+ # Decide what to do with the argument
109
+ puts "DEBUG main: #{filetype(arg_ref).inspect}"
110
+ case filetype(arg_ref)
111
+ when :tarball
112
+ @cabinet = Purple.cabinet_from_url arg_ref
113
+ when :script
114
+ @cabinet = Purple::Script.open URI.parse(arg_ref).path
115
+ else
116
+ raise "Unknown file type of argument '#{arg_ref}'"
117
+ end
118
+ p @cabinet
119
+
120
+ error = catch :stop do
121
+ @cabinet.setup
122
+
123
+ @cabinet.run_steps steps
124
+
125
+ if OPTIONS.has_key? 'make' or OPTIONS.has_key? 'deploy'
126
+ Purple::Platform.detect
127
+ @cabinet.make
128
+ end
129
+
130
+ if OPTIONS.has_key? 'deploy'
131
+ puts "DEBUG: Doing deploy"
132
+ @cabinet.deploy
133
+ end
134
+
135
+ :normal_complete
136
+ end
137
+
138
+ if :normal_complete != error
139
+ STDERR.puts "An error condition was encountered and forced a stop."
140
+ STDERR.puts "Reason: #{error}" if error
141
+ end
@@ -0,0 +1,34 @@
1
+ require 'uri'
2
+
3
+ module Purple
4
+ module Getter
5
+ def self.new url, destdir
6
+ puts "DEBUG Getter##new: url=#{url}"
7
+ @uri = URI.parse url
8
+ plugin = case @uri.scheme
9
+ when /http|ftp/
10
+ 'wget'
11
+ when 'file'
12
+ 'cp'
13
+ else
14
+ raise StandardError.new("Unable to handle scheme #{@uri.scheme}")
15
+ end
16
+ require "purple/getter_#{plugin}"
17
+ (eval "Purple::Getter::Getter_#{plugin}").new @uri, destdir
18
+ end
19
+
20
+ class Generic
21
+ # -> anIO
22
+ def initialize uri, destdir
23
+ self.uri = uri
24
+ @status = 'Getting'
25
+ @destdir = destdir
26
+ end
27
+ attr_accessor :uri, :length, :content_type
28
+ attr_reader :thread
29
+
30
+ # def get -> nil
31
+ # def get_status -> anArray [status, %done]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ require 'open3'
2
+
3
+ module Purple
4
+ module Getter
5
+ class Getter_cp < Generic
6
+ def get
7
+ if system "ln '#{@uri.path}' '#{@destdir}/'"
8
+ @done = '100'
9
+ @status = 'Done'
10
+ else
11
+ @done = '100'
12
+ @status = 'Error'
13
+ end
14
+ end
15
+
16
+ def get_status
17
+ [@status, @done]
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,105 @@
1
+ require 'open3'
2
+
3
+ module Purple
4
+ module Getter
5
+ class Getter_wget < Generic
6
+ def initialize *args
7
+ super
8
+ @done = "0"
9
+ end
10
+
11
+ def get
12
+ @thread = Thread.new do
13
+ filename = File.basename uri.path
14
+ Open3.popen3 "wget --progress dot -O '#{@destdir}/#{filename}' #{@uri.to_s} 2>&1" do
15
+ |pw, pr, pe|
16
+ parse_input pw, pr, pe
17
+ end
18
+ end
19
+ end
20
+
21
+ def get_status
22
+ [@status, @done]
23
+ end
24
+
25
+ # wget specific methods
26
+
27
+ def parse_input pw, pr, pe
28
+ #puts "DEBUG Getter_wget#parse_input: Start"
29
+
30
+ loop do
31
+ # Start line
32
+ 2.times { pr.gets }
33
+
34
+ # Host lookup
35
+ #puts "DEBUG Getter_wget#parse_input: Host lookup"
36
+ line = pr.gets
37
+ #puts "->#{line}"
38
+ if line =~ /failed:/
39
+ @status = 'Host lookup failed'
40
+ return
41
+ end
42
+
43
+ # Connecting
44
+ #puts "DEBUG Getter_wget#parse_input: Connecting"
45
+ line = pr.gets
46
+ #puts "->#{line}"
47
+ md = /^Connecting to (.*?)... (.*?)$/.match line
48
+ #puts "DEBUG Getter_wget#parse_input: md[2]=#{md[2].inspect}"
49
+
50
+ unless 'connected.' == md[2]
51
+ @status = 'Connection failed'
52
+ return
53
+ end
54
+
55
+ # Request
56
+ #puts "DEBUG Getter_wget#parse_input: Sending request"
57
+ line = pr.gets
58
+ #puts "->#{line}"
59
+ md = /HTTP request sent, awaiting response... (.*)/.match line
60
+ case md[1]
61
+ when '200 OK'
62
+ # Okay. Continue
63
+ when /^3\d{2}/
64
+ # Redirection
65
+ pr.gets # Location line
66
+ redo
67
+ else
68
+ @status = md[1]
69
+ return
70
+ end
71
+
72
+ break
73
+ end
74
+
75
+ # Content details
76
+ line = pr.gets
77
+ #puts "->#{line}"
78
+ md = /Length: (.*?) \[(.*?)\]/.match line
79
+ @length = md[1].gsub(',', '').to_i
80
+ @content_type = md[2]
81
+
82
+ # Empty line
83
+ pr.gets
84
+
85
+ # Data incoming
86
+ pr.each do |line|
87
+ #puts "->#{line}"
88
+
89
+ md = / *([0-9]+)K[ \.]+([0-9]+)% +([0-9\.,]+ KB\/s)/.match line
90
+ #puts (md ? "DEBUG #{md.to_a.inspect}" : "DEBUG nil")
91
+ if md
92
+ @done = md[2]
93
+ @rate = md[3]
94
+ next
95
+ end
96
+
97
+ if "100" == @done
98
+ @status = "Done"
99
+ end
100
+ pr.read
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,59 @@
1
+
2
+ module Purple
3
+
4
+ # Makefile aware predicate container. Initialize with path
5
+ # to source directory.
6
+ class MakefileMaven
7
+ def initialize srcdir
8
+ @srcdir = srcdir
9
+ end
10
+
11
+ def has_makefile?
12
+ makefilename && true
13
+ end
14
+
15
+ def makefilename
16
+ return @makefilename if defined? @makefilename
17
+ @makefilename = ['GNUmakefile', 'makefile', 'Makefile'].find do |name|
18
+ puts "DEBUG MakefileMaven#makefilename: testing #{File.join(@srcdir, name)}"
19
+ FileTest.exist? File.join(@srcdir, name)
20
+ end
21
+ end
22
+
23
+ def uses_prefix?
24
+ return true if makefile_rules.grep(/^prefix/).size > 0
25
+ false
26
+ end
27
+
28
+ def uses_destdir?
29
+ return true if makefile_rules.grep(/DESTDIR/).size > 0
30
+ false
31
+ end
32
+
33
+ def makefile_rules
34
+ return @rules if defined? @rules
35
+ @rules = `make -pn -C #{@srcdir}`
36
+ end
37
+
38
+ def makefile_contents
39
+ return @contents if defined? @contents
40
+
41
+ @contents = ''
42
+ files = [makefilename];
43
+ while files.size > 0
44
+ filename = File.join(@srcdir, files.shift)
45
+ if FileTest.exist? filename
46
+ puts "DEBUG MakefileMaven#makefile_contents: loop->if"
47
+ text = File.open(filename) { |f| f.read }
48
+ @contents << text
49
+ text.grep(/^include /).each do |s|
50
+ md = /^include (.*?)\n$/.match s
51
+ files << md[1]
52
+ end
53
+ end
54
+ end
55
+ puts "DEBUG MakefileMaven#makefile_contents: #{@contents.to_a.size} lines"
56
+ @contents
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module Purple
3
+
4
+ module Matches
5
+ EXTENSIONS = '(\.tar\.gz|\.tar\.bz2|\.tgz|\.zip)'
6
+ REGEXPS = [
7
+ /^(.+)-((\d+)(\.\d+)*(-?\w+)?)#{EXTENSIONS}$/,
8
+ /^(.+)\.([^\.]+?)#{EXTENSIONS}$/,
9
+ ];
10
+
11
+ def self.match_filename filename
12
+ md = nil
13
+ REGEXPS.find { |r| md = r.match filename }
14
+ #puts "DEBUG Matches#match_filename: filename=#{filename.inspect} md=#{md.to_a.inspect}"
15
+ raise 'filename does not match pattern' if not (md and not md.to_a[0..1].include? nil)
16
+
17
+ { :name => md[1], :version => md[2] }
18
+ end
19
+ end
20
+ end
data/lib/purple/osx.rb ADDED
@@ -0,0 +1,117 @@
1
+
2
+ module Purple
3
+
4
+ PACKAGE_DESCRIPTION_TEMPLATE = proc do |pkg| <<EOS
5
+ <?xml version="1.0" encoding="UTF-8"?>
6
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
7
+ <plist version="1.0">
8
+ <dict>
9
+ <key>IFPkgDescriptionTitle</key>
10
+ <string>#{pkg.name}</string>
11
+ <key>IFPkgDescriptionVersion</key>
12
+ <string>#{pkg.version}</string>
13
+ </dict>
14
+ </plist>
15
+ EOS
16
+ end
17
+
18
+
19
+ PACKAGE_INFO_TEMPLATE = proc do |pkg| <<EOS
20
+ <?xml version="1.0" encoding="UTF-8"?>
21
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
22
+ <plist version="1.0">
23
+ <dict>
24
+ <!--
25
+ <key></key>
26
+ <string></string>
27
+ ***
28
+ -->
29
+ <key>CFBundleGetInfoString</key>
30
+ <string>#{pkg.info_string}</string>
31
+ <key>CFBundleIdentifier</key>
32
+ <string>#{pkg.identifier}</string>
33
+ <key>CFBundleName</key>
34
+ <string>#{pkg.name}</string>
35
+ <key>CFBundleShortVersionString</key>
36
+ <string>#{pkg.version}</string>
37
+ <key>IFMajorVersion</key>
38
+ <integer>#{pkg.major}</integer>
39
+ <key>IFMinorVersion</key>
40
+ <integer>#{pkg.minor}</integer>
41
+ <key>IFPkgFlagAllowBackRev</key>
42
+ <false/>
43
+ <key>IFPkgFlagAuthorizationAction</key>
44
+ <string>AdminAuthorization</string>
45
+ <key>IFPkgFlagDefaultLocation</key>
46
+ <string>/</string>
47
+ <key>IFPkgFlagInstallFat</key>
48
+ <false/>
49
+ <key>IFPkgFlagIsRequired</key>
50
+ <false/>
51
+ <key>IFPkgFlagOverwritePermissions</key>
52
+ <true/>
53
+ <key>IFPkgFlagRelocatable</key>
54
+ <false/>
55
+ <key>IFPkgFlagRestartAction</key>
56
+ <string>NoRestart</string>
57
+ <key>IFPkgFlagRootVolumeOnly</key>
58
+ <true/>
59
+ <key>IFPkgFlagUpdateInstalledLanguages</key>
60
+ <false/>
61
+ <key>IFPkgFlagUseUserMask</key>
62
+ <false/>
63
+ <key>IFPkgFormatVersion</key>
64
+ <real>0.10000000149011612</real>
65
+ </dict>
66
+ </plist>
67
+ EOS
68
+ end
69
+
70
+ class PackageInfo
71
+ def info_string; long_name; end
72
+ end
73
+
74
+ class PurpleCabinet
75
+ def osx_stage
76
+ assert_dir "#{@cabinet_dir}"
77
+ assert_dir "#{@cabinet_dir}/OsxStage"
78
+ assert_dir File.join(@cabinet_dir, 'OsxStage')
79
+ end
80
+
81
+ def make
82
+ packages.each do |pkg|
83
+ system "rm -r '#{osx_stage}'"
84
+ File.open "#{osx_stage}/Description.plist", "w" do |f|
85
+ f.puts pkg.description
86
+ end
87
+
88
+ Dir.mkdir "#{osx_stage}/Resources"
89
+ File.open "#{osx_stage}/Resources/Welcome.txt", "w" do |f|
90
+ f.print <<-EOS
91
+ Hello, World!
92
+ EOS
93
+ end
94
+
95
+ File.open "#{osx_stage}/Info.plist", "w" do |f|
96
+ f.print PACKAGE_INFO_TEMPLATE.call(pkg)
97
+ end
98
+
99
+ File.open "#{osx_stage}/Description.plist", "w" do |f|
100
+ f.print PACKAGE_DESCRIPTION_TEMPLATE.call(pkg)
101
+ end
102
+
103
+ system "/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker " +
104
+ "-build -p '#{packagedir}/#{pkg.name}.pkg' -f '#{pkg.stage_root}' -r '#{osx_stage}/Resources' " +
105
+ "-d '#{osx_stage}/Description.plist' -i '#{osx_stage}/Info.plist'"
106
+ end
107
+ end
108
+
109
+
110
+ def deploy
111
+ packages.each do |pkg|
112
+ system "open '#{File.join packagedir, pkg.name}.pkg'"
113
+ end
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,95 @@
1
+
2
+ module Purple
3
+ module PackageActions
4
+
5
+ attr_accessor :cabinet
6
+
7
+ def self.package_method name
8
+ prg = <<-EOS
9
+ def #{name}
10
+ if defined? @method_#{name}_package and @method_#{name}_package
11
+ return @method_#{name}_package.call(self)
12
+ else
13
+ m = self.method "default_#{name}"
14
+ return(m.call) if m
15
+ end
16
+ end
17
+ def #{name}= prc
18
+ @method_#{name}_package = prc
19
+ end
20
+ EOS
21
+ #puts prg
22
+ module_eval prg
23
+ end
24
+
25
+ def srcdir
26
+ return @srcdir if defined? @srcdir
27
+ dirs = Dir.new(cabinet.srcdir).reject { |s| s =~ /^\.{1,2}$/ }
28
+ if 1 == dirs.size
29
+ @srcdir = "#{cabinet.srcdir}/#{dirs[0]}"
30
+ else
31
+ @srcdir = Dir.new(cabinet.srcdir).find { |s| s =~ Regexp.new('^' + Regexp.escape(name)) }
32
+ end
33
+ throw :stop, "Unable to determine source directory for package #{name}" if not @srcdir
34
+ puts "Choosing #{@srcdir} as source code folder"
35
+ @srcdir
36
+ end
37
+
38
+ def stage_root
39
+ File.join cabinet.stage_root, long_name
40
+ end
41
+
42
+ package_method :prepare
43
+ package_method :config
44
+ package_method :build
45
+ package_method :stage
46
+ package_method :make
47
+
48
+ def default_prepare
49
+ puts "DEBUG PackageActions#default_prepare"
50
+ files.each do |f|
51
+ unpack = case f
52
+ when /gz$/; '-z'
53
+ when /bz2$/; '-j'
54
+ else ''
55
+ end
56
+ if not Purple.sys "tar x #{unpack} -C '#{cabinet.srcdir}' -f #{cabinet.filesdir}/#{f}"
57
+ throw :stop
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ def default_config
64
+ throw :stop unless system "cd #{srcdir}; ./configure --prefix=/usr"
65
+ end
66
+
67
+ def default_build
68
+ throw :stop unless system "make -C '#{srcdir}'"
69
+ end
70
+
71
+ def default_stage
72
+ system "rm -fr '#{stage_root}/*'"
73
+
74
+ require 'purple/makefile'
75
+
76
+ puts "DEBUG PackageActions#default_stage: srcdir=#{srcdir}"
77
+ mkm = MakefileMaven.new srcdir
78
+ if mkm.uses_prefix?
79
+ if mkm.uses_destdir?
80
+ make_args = "DESTDIR='#{stage_root}'"
81
+ else
82
+ make_args = "prefix='#{stage_root}/usr'"
83
+ end
84
+ else
85
+ if mkm.uses_destdir?
86
+ make_args = "DESTDIR='#{stage_root}'"
87
+ else
88
+ raise 'Unable to find a way to stage! Package neither defines prefix or DESTDIR'
89
+ end
90
+ end
91
+
92
+ throw :stop if not system "make -C '#{srcdir}' #{make_args} install"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,15 @@
1
+
2
+ module Purple
3
+ module Platform
4
+ def self.detect
5
+ case true
6
+ when FileTest.exist?('/etc/debian_version')
7
+ system_brand = :debian
8
+ when (FileTest.directory?('/System/Library/') and FileTest.file?('/mach_kernel'))
9
+ system_brand = :osx
10
+ end
11
+
12
+ require "purple/#{system_brand}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,172 @@
1
+ require 'singleton'
2
+ require 'uri'
3
+ require 'purple'
4
+
5
+
6
+ PURPLE_SCRIPT_TEMPLATE = proc do |cabinet| <<EOS
7
+ # Autogenerated Purple Packaging script.
8
+ # Cabinet name: '#{cabinet.name}'
9
+
10
+ name #{cabinet.name.inspect}
11
+ long_name #{cabinet.long_name.inspect}
12
+
13
+ #{ cabinet.urls.collect { |k,v| "url #{v.inspect}\n" } }
14
+
15
+ #{
16
+ cabinet.packages.collect { |pkg| PURPLE_PACKAGE_TEMPLATE.call pkg }
17
+ }
18
+ EOS
19
+ end
20
+
21
+ PURPLE_PACKAGE_TEMPLATE = proc do |pkg| <<EOS
22
+ package(#{pkg.name.inspect}) { |p|
23
+ #{pkg.files.collect{ |s| " p.file #{s.inspect}" }.join("\n") }
24
+ p.long_name #{pkg.long_name.inspect}
25
+ p.identifier #{pkg.identifier.inspect}
26
+ p.version #{pkg.version.inspect}
27
+ p.major #{pkg.major}
28
+ p.minor #{pkg.minor}
29
+
30
+ # Uncomment and modify for special configuration
31
+ #p.config proc { |pkg|
32
+ # throw :stop unless system "cd \#{pkg.srcdir}; ./configure --prefix=/usr"
33
+ #}
34
+
35
+ }
36
+ EOS
37
+ end
38
+
39
+ module Purple
40
+ class Script
41
+ def self.open filename
42
+ parse File.open(filename).read
43
+ end
44
+
45
+ def self.parse string
46
+ script = self.new
47
+ script.instance_eval string
48
+ puts "DEBUG Purple::Script##parse: cabinet=#{script.cabinet}"
49
+ script.cabinet
50
+ end
51
+
52
+ def initialize
53
+ @cabinet = PurpleCabinet.new
54
+ @package_scripts = Array.new
55
+ end
56
+ attr_reader :cabinet
57
+
58
+ def name name
59
+ @cabinet.name = name
60
+ end
61
+
62
+ def long_name name
63
+ @cabinet.long_name = name
64
+ end
65
+
66
+ def url url
67
+ @cabinet.add_url url
68
+ end
69
+
70
+ def package name=nil
71
+ puts "> #package(#{name.inspect})"
72
+ package = PackageScript.new @cabinet
73
+ @package_scripts << package
74
+ package.name name
75
+ yield package if block_given?
76
+ end
77
+
78
+ def infer
79
+ if not @cabinet.long_name
80
+ @cabinet.long_name = @cabinet.packages[0].long_name
81
+ end
82
+ if not @cabinet.name
83
+ @cabinet.name = @cabinet.packages[0].name
84
+ end
85
+ end
86
+
87
+ def infer_all
88
+ @package_scripts.each { |pkg|
89
+ puts "DEBUG PurpleScript#infer_all"
90
+ pkg.infer
91
+ }
92
+ puts "DEBUG PurpleScript#infer_all: b4end"
93
+ infer
94
+ end
95
+
96
+ def self.write cabinet, filename
97
+ File.open filename, 'w' do |f|
98
+ f.write dump(cabinet)
99
+ end
100
+ end
101
+ def self.dump cabinet
102
+ PURPLE_SCRIPT_TEMPLATE.call cabinet
103
+ end
104
+
105
+ class PackageScript
106
+ def self.callthrough (*ss)
107
+ ss.each do |s|
108
+ module_eval <<-EOS
109
+ def #{s} value
110
+ @package.#{s} = value
111
+ end
112
+ EOS
113
+ end
114
+ end
115
+
116
+ def initialize cabinet
117
+ @package = cabinet.create_package
118
+ @cabinet = cabinet
119
+ puts "DEBUG PackageScript#initialize: @package=#{@package}"
120
+ end
121
+
122
+ callthrough :long_name, :name, :identifier, :version, :major, :minor
123
+ callthrough :prepare, :config, :build, :stage, :make
124
+
125
+ def pkg
126
+ @package
127
+ end
128
+
129
+ def file filename
130
+ pkg.files << filename
131
+ end
132
+
133
+ def infer
134
+ puts "DEBUG #infer"
135
+ puts "DEBUG PackageScript#infer: pkg=#{pkg}"
136
+ # Take a guess at the filename
137
+ if 0 == pkg.files.size
138
+ files = @cabinet.files
139
+ puts "DEBUG #infer: cabinet_files=#{files.inspect}"
140
+ if 0 == files.size
141
+ warn 'Cabinet files section is empty. Did you not specify any urls?'
142
+ else
143
+ if pkg.long_name
144
+ # See if any filenames match the long name
145
+ rs = files.grep Regexp.new(Regexp.escape(pkg.long_name))
146
+ file rs[0] if 1 == rs.size
147
+ else
148
+ # Else just guess that the first file is the right one
149
+ file files[0]
150
+ end
151
+ end
152
+ end
153
+
154
+ #puts "DEBUG #infer: pkg.files=#{pkg.files.inspect}"
155
+ #puts "DEBUG #infer: long_name=#{pkg.long_name}"
156
+ # Take a guess at properties long_name, name, version, major, and minor
157
+ md = Matches.match_filename pkg.files[0]
158
+ puts "DEBUG #infer: filename match result #{md.inspect}"
159
+
160
+ pkg.long_name = "#{md[:name]}-#{md[:version]}" if not pkg.long_name
161
+ pkg.name = md[:name] if not pkg.name
162
+ pkg.version = md[:version] if not pkg.version
163
+
164
+ md = /^([0-9]+)\.([0-9]+).*/.match pkg.version
165
+ pkg.major = md[1] if md and not pkg.major
166
+ pkg.minor = md[2] if md and not pkg.minor
167
+
168
+ end
169
+ end
170
+
171
+ end
172
+ end
data/lib/purple.rb ADDED
@@ -0,0 +1,221 @@
1
+ require 'singleton'
2
+ require 'fileutils'
3
+
4
+ module Purple
5
+ autoload :PackageActions, 'purple/pkg_actions'
6
+ autoload :Getter, 'purple/getter'
7
+ autoload :Script, 'purple/script'
8
+ autoload :Matches, 'purple/matches'
9
+ autoload :Platform, 'purple/platform'
10
+ PURPLE_FOLDER = "#{ENV['HOME']}/purple"
11
+
12
+
13
+ class PurpleCabinet
14
+ def initialize
15
+ @packages = Array.new
16
+ @urls = Hash.new
17
+ @files = Array.new
18
+ end
19
+ attr_accessor :name, :long_name
20
+ attr_reader :urls, :files, :packages, :cabinet_dir
21
+
22
+ # -> aString # Get source dir
23
+ def filesdir
24
+ assert_dir File.join(@cabinet_dir, 'Files')
25
+ end
26
+
27
+ def srcdir
28
+ assert_dir File.join(@cabinet_dir, 'Source')
29
+ end
30
+
31
+ def stage_root
32
+ assert_dir File.join(@cabinet_dir, 'StageRoot')
33
+ end
34
+
35
+ def packagedir
36
+ assert_dir File.join(@cabinet_dir, 'Package')
37
+ end
38
+
39
+ def fetch_all
40
+ urls.each do |url|
41
+ Getter.get url, filesdir
42
+ end
43
+ end
44
+
45
+ def add_url url
46
+ filename = File.basename URI.parse(url).path
47
+ @urls[filename] = url
48
+ @files << filename
49
+ end
50
+
51
+ def setup
52
+ raise 'cabinet long_name not properly set' if not long_name
53
+ @cabinet_dir = File.join(PURPLE_FOLDER, long_name)
54
+ assert_dir @cabinet_dir
55
+ end
56
+
57
+ def fetch filename
58
+ if not FileTest.exist? "#{filesdir}/#{filename}"
59
+ g = Getter.new urls[filename], filesdir
60
+ g.get
61
+ status = 'Getting'
62
+ loop do
63
+ status, done = *(g.get_status)
64
+ printf "\015\033[MFetching %-40s %3d%% %s", filename, done, status
65
+ $defout.flush
66
+ sleep 1
67
+ break if 'Getting' != status
68
+ end
69
+ puts
70
+ throw :stop, "There was an error while fetching file #{filename}" unless 'Done' == status
71
+ end
72
+ end
73
+
74
+ def prepare
75
+ @packages.each do |p|
76
+ p.files.each { |f| fetch f }
77
+ p.prepare
78
+ end
79
+ end
80
+
81
+ def config
82
+ @packages.each { |p|
83
+ return false if not p.config
84
+ }
85
+ end
86
+
87
+ def build
88
+ @packages.each { |p|
89
+ return false if not p.build
90
+ }
91
+ end
92
+
93
+ def stage
94
+ @packages.each { |p|
95
+ return false if not p.stage
96
+ }
97
+ end
98
+
99
+ def deps
100
+ true
101
+ end
102
+
103
+ def run_steps steps=[:prepare, :build, :deps, :make]
104
+ steps.each do |step|
105
+ self.method(step).call
106
+ end
107
+ end
108
+
109
+ ## ##
110
+
111
+ def create_package
112
+ p = PackageInfo.new
113
+ class <<p
114
+ include PackageActions
115
+ end
116
+ p.cabinet = self
117
+ @packages << p
118
+ @packages.last
119
+ end
120
+
121
+ ## ##
122
+
123
+ def assert_dir path
124
+ unless FileTest.exist? path
125
+ puts ">- Creating folder #{path}"
126
+ Dir.mkdir path
127
+ end
128
+ (FileTest.directory? path) ? path : nil
129
+ end
130
+
131
+ end
132
+
133
+ class PackageInfo
134
+ def initialize
135
+ @files = []
136
+ end
137
+ attr_accessor :long_name, :name, :version, :major, :minor, :identifier, :description
138
+ attr_reader :files
139
+ end
140
+
141
+ class PurpleFile
142
+ def self.parse str
143
+ pkg = PackageInfo.new
144
+ receiver_stack = ['main']
145
+ str.split(/(\r\n|\r|\n)+/).each do |line|
146
+ r = self.method("__#{receiver_stack.last}").call line.strip, pkg
147
+ case r
148
+ when -1
149
+ receiver_stack.pop
150
+ when nil
151
+ else
152
+ receiver_stack.push r
153
+ end
154
+ end
155
+ pkg
156
+ end
157
+
158
+ def self.__main line, pkg
159
+ case line
160
+ when /^package/
161
+ pkg.name = line.gsub(/^package\s+/, '')
162
+ return 'package'
163
+ end
164
+ end
165
+
166
+ PROPS = 'longname|version|major|minor|identifier|description|url'
167
+ def self.__package line, pkg
168
+ if (md = Regexp.new("^(#{PROPS})\s+(.*)$").match line)
169
+ pkg.method("#{md[1]}=").call md[2]
170
+ else
171
+ self.infer_properties pkg if line == 'infer'
172
+ end
173
+ nil
174
+ end
175
+
176
+ def self.infer_properties pkg
177
+ if pkg.url
178
+ if pkg.url =~ /prdownloads.sourceforge.net/
179
+ md = Regexp.new 'http://prdownloads.sourceforge.net/([^/])/(.*?)tar.(gz|bz2)?download'
180
+ pkg.long_name = md[2]
181
+ end
182
+ end
183
+
184
+ pkg.long_name = File.basename Dir.pwd if not pkg.long_name
185
+
186
+ md = /([a-z\-]+)-([0-9\-\.]+.*)/.match pkg.long_name
187
+ pkg.version = md[2] if not pkg.version
188
+
189
+ md = /^([0-9]+)\.([0-9]+)/.match pkg.version
190
+ pkg.major = md[1] if not pkg.major
191
+ pkg.minor = md[2] if not pkg.minor
192
+
193
+ end
194
+ end
195
+
196
+ def self.cabinet_from_url url
197
+
198
+ cabinet = Purple::Script.parse(<<-EOS
199
+ url #{url.inspect}
200
+ package # {|pkg| pkg.infer }
201
+ infer_all
202
+ EOS
203
+ )
204
+ cabinet.setup
205
+ Purple::Script.write cabinet, File.join(cabinet.cabinet_dir, cabinet.name + '.purple')
206
+ cabinet
207
+ end
208
+
209
+ def self.sys cmd
210
+ system cmd
211
+ end
212
+
213
+ end
214
+
215
+ module Kernel
216
+ alias_method :_system_, :system
217
+ def system(*args)
218
+ puts "> #{args.join " "}"
219
+ _system_(*args)
220
+ end
221
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.1
3
+ specification_version: 1
4
+ name: purplepkg
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.3
7
+ date: 2004-11-12
8
+ summary: A simple pre-packing tool with meta-package plugin support.
9
+ require_paths:
10
+ - lib
11
+ author: Simon Conrad-Armes
12
+ email: curne@curnomatic.dk
13
+ homepage: purplepkg.rubyforge.org
14
+ rubyforge_project: purple
15
+ description:
16
+ autorequire:
17
+ default_executable:
18
+ bindir: bin
19
+ has_rdoc: false
20
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
21
+ requirements:
22
+ -
23
+ - ">"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.0
26
+ version:
27
+ platform: ruby
28
+ files:
29
+ - lib/purple
30
+ - lib/purple.rb
31
+ - lib/purple/matches.rb
32
+ - lib/purple/getter_cp.rb
33
+ - lib/purple/getter_wget.rb
34
+ - lib/purple/osx.rb
35
+ - lib/purple/pkg_actions.rb
36
+ - lib/purple/script.rb
37
+ - lib/purple/makefile.rb
38
+ - lib/purple/getter.rb
39
+ - lib/purple/platform.rb
40
+ - bin/purple
41
+ - bin/install_ruby
42
+ test_files: []
43
+ rdoc_options: []
44
+ extra_rdoc_files: []
45
+ executables:
46
+ - purple
47
+ extensions: []
48
+ requirements: []
49
+ dependencies: []