Skip to content

Commit

Permalink
Added checksum generation and validation, arch support in filename an…
Browse files Browse the repository at this point in the history
…d for sources
  • Loading branch information
krobertson committed Apr 26, 2012
1 parent b9cefce commit ae13190
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 23 deletions.
11 changes: 10 additions & 1 deletion lib/claw/builder/cli.rb
Expand Up @@ -37,7 +37,7 @@ def build(formula)

# initiate the build
puts ">> Uploading code for build"
res = RestClient.post "http://localhost:8080/build", manifest
res = RestClient.post "http://localhost:8080/build", manifest.to_json, :content_type => :json, :accept => :json
res = JSON.parse(res)

puts ">> Tailing build..."
Expand All @@ -50,8 +50,17 @@ def build(formula)
if data.first['success']
puts ">> Build complete"
puts " Build available from #{data.first['package_url']}"
if data.first['checksums']
puts " Checksums:"
data.first['checksums'].keys.sort.each do |algo|
puts "#{algo.upcase.rjust(12)}: #{data.first['checksums'][algo]}"
end
end
else
puts ">> Build FAILED!"
if data.first['error_message']
puts " Error: #{data.first['error_message']}"
end
end
end
end
Expand Down
8 changes: 7 additions & 1 deletion lib/claw/builder/package_formula.rb
Expand Up @@ -28,6 +28,11 @@ def include_file(name, opts={})
@spec[:included_files]
end

def noarch(val=true)
@spec[:noarch] = val
@spec[:noarch]
end

def build
@spec[:build_script] = yield if block_given?
@spec[:build_script]
Expand All @@ -52,7 +57,8 @@ def init_package_spec
:version => '0.0.1',
:sources => [],
:dependencies => [],
:included_files => []
:included_files => [],
:noarch => false
}
end

Expand Down
80 changes: 60 additions & 20 deletions server/builder.coffee
@@ -1,3 +1,4 @@
crypto = require('crypto')
fs = require('fs')
path = require('path')
url = require('url')
Expand All @@ -13,37 +14,51 @@ class Builder extends EventEmitter
constructor: (@spec) ->
@output = {}

# normalize the nodejs arch
switch require('os').arch()
when 'x64' then @arch = 'x86_64'
when 'ia32' then @arch = 'i386'
@build_arch = @arch
@build_arch = 'all' if @spec.noarch

# file info
@workingDirectory = temp.mkdirSync('working')
@packageDirectory = temp.mkdirSync('package')
@packageFilename = "#{@packageDirectory}/#{@spec.name}-#{@spec.version}.tar.gz"

# sources seems to not be an array if there is only one element
if @spec.sources not instanceof Array
@spec.sources = [ @spec.sources ]
@packageBaseName = "#{@spec.name}-#{@spec.version}-#{@arch}.tar.gz"
@packageFilename = "#{@packageDirectory}/#{@packageBaseName}"

# setup s3 client
@s3_client = knox.createClient({
key: process.env.S3_KEY,
secret: process.env.S3_SECRET,
bucket: process.env.S3_BUCKET
})
@s3_path = "#{@spec.name}/#{@spec.name}-#{@spec.version}.tar.gz"
@s3_path = "#{@spec.name}/#{@packageBaseName}"

process: ->
if @spec.sources
@_downloadSources()
else
@_runBuild()
@_downloadSources()

_downloadSources: ->
# download each source
async.forEach(@spec.sources, (source, clbk) =>
async.forEachSeries(@spec.sources, (source, clbk) =>
if source.arch
return clbk() if source.arch != @arch
this.emit 'data', "Downloading #{source.url}\n"
@_downloadFile(source, clbk)
@_downloadFile source, (path) =>
async.forEach(['md5','sha1','sha256'], (algo,vcb) =>
if source[algo]
@_validateFile path, algo, source[algo], vcb
else
vcb()
, (err) =>
if err
clbk(err)
else
clbk()
)
, (err) =>
if err
@_finish(false)
@_finish(false, err)
else
@_runBuild()
)
Expand Down Expand Up @@ -88,18 +103,28 @@ class Builder extends EventEmitter
if path.existsSync(log)
@output.packaging_log = fs.readFileSync(log).toString()
if code == 0
# send it to s3 if it exited ok
this.emit 'data', "Uploading to S3...\n"
@s3_client.putFile @packageFilename, @s3_path, (err,res) =>
@output.package_url = @s3_client.url(@s3_path)
@_finish(true)
# generate checksums
this.emit 'data', "Generating checksums...\n"
@output.checksums = {}
async.forEach(['md5','sha1','sha256'], (algo,cb) =>
@_checksumFile @packageFilename, algo, (c) =>
@output.checksums[algo] = c
cb()
, =>
# send it to s3 if it exited ok
this.emit 'data', "Uploading to S3...\n"
@s3_client.putFile @packageFilename, @s3_path, (err,res) =>
@output.package_url = @s3_client.url(@s3_path)
@_finish(true)
)
runner.run()

_finish: (success) ->
_finish: (success, err) ->
# cleanup and emit we're done
wrench.rmdirSyncRecursive @workingDirectory
wrench.rmdirSyncRecursive @packageDirectory
@output.success = success
@output.error_message = err if !success
this.emit 'done', @output

_setupRunner: (runner) ->
Expand All @@ -123,7 +148,22 @@ class Builder extends EventEmitter
http.get options, (res) =>
res.pipe(file)
res.on 'end', =>
cb() if cb
cb "#{@workingDirectory}/#{filename}" if cb

_checksumFile: (path,algo,cb) ->
hash = crypto.createHash algo
file = fs.createReadStream(path)
file.on 'data', (data) =>
hash.update data
file.on 'end', =>
cb hash.digest('hex')

_validateFile: (path,algo,expected,cb) ->
@_checksumFile path, algo, (checksum) =>
if checksum == expected
cb()
else
cb("#{algo} for #{path.split('/').pop()} checksum didn't match")

createBuilder = (spec) -> new Builder spec
module.exports = createBuilder
4 changes: 3 additions & 1 deletion server/worker.coffee
Expand Up @@ -35,7 +35,9 @@ nats.subscribe "claw.builder.worker", (msg,reply) ->
complete_message = {
task_id: message.task_id,
package_url: output.package_url,
success: output.success
success: output.success,
checksums: output.checksums,
error_message: output.error_message
}
io.sockets.emit 'complete', complete_message

Expand Down

0 comments on commit ae13190

Please sign in to comment.