jsrebuild 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +2 -0
- data/History.txt +5 -0
- data/LICENSE +28 -0
- data/README.md +55 -0
- data/bin/jsrebuild +57 -0
- data/jsrebuild.gemspec +32 -0
- data/lib/jsrebuild.rb +17 -0
- data/lib/jsrebuild/config.rb +18 -0
- data/lib/jsrebuild/runner.rb +64 -0
- data/lib/jsrebuild/version.rb +3 -0
- data/lib/jsrebuild/watcher.rb +112 -0
- data/test/Jakefile +1 -0
- data/test/jake.yml +18 -0
- data/test/source/fake_core.js +1 -0
- data/test/source/fake_ui.js +3 -0
- metadata +107 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/History.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Copyright (c) 2011, the OTHER media.
|
2
|
+
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright notice,
|
9
|
+
this list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
13
|
+
and/or other materials provided with the distribution.
|
14
|
+
|
15
|
+
* Neither the name of the OTHER media nor the names of other contributors
|
16
|
+
may be used to endorse or promote products derived from this software
|
17
|
+
without specific prior written permission.
|
18
|
+
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
20
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
21
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
23
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
24
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
25
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
26
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
jsrebuild
|
2
|
+
=========
|
3
|
+
|
4
|
+
**jsrebuild** dynamically runs the [Jake] build tool to rebuild JavaScript
|
5
|
+
projects in development environments.
|
6
|
+
|
7
|
+
[Jake]: https://github.com/jcoglan/jake
|
8
|
+
|
9
|
+
Overview
|
10
|
+
--------
|
11
|
+
|
12
|
+
Jake is often run as part of a website's build process, building JavaScript
|
13
|
+
packages from source files. This often leads to a tedious situation for
|
14
|
+
projects which use Jake, as the developer must continually run the `jake`
|
15
|
+
command to rebuild their JavaScript files as they make changes to the source
|
16
|
+
code.
|
17
|
+
|
18
|
+
The `jsrebuild` utility provides a solution to this problem: it watches a
|
19
|
+
source directory and rebuilds the project whenever changes are made to the
|
20
|
+
source files, `jake.yml` config file and the `Jakefile` helper file.
|
21
|
+
|
22
|
+
|
23
|
+
Installation
|
24
|
+
------------
|
25
|
+
|
26
|
+
jsrebuild uses the [Cool.io] library which depends on [libev], a low-level
|
27
|
+
event loop library, so you will need to have libev installed before attempting
|
28
|
+
to install the jsrebuild gem.
|
29
|
+
|
30
|
+
jsrebuild is available from RubyGems, so you can install it and its
|
31
|
+
dependencies simply by running
|
32
|
+
|
33
|
+
gem install jsrebuild
|
34
|
+
|
35
|
+
[cool.io]: https://github.com/tarcieri/cool.io
|
36
|
+
[libev]: http://software.schmorp.de/pkg/libev.html
|
37
|
+
|
38
|
+
|
39
|
+
Running `jsrebuild`
|
40
|
+
-------------------
|
41
|
+
|
42
|
+
To watch a particular directory such as `~/projects/mywebapp` for changes, just
|
43
|
+
run
|
44
|
+
|
45
|
+
jsrebuild ~/projects/mywebapp
|
46
|
+
|
47
|
+
The `jsrebuild` tool takes a number of command-line arguments, allowing you to
|
48
|
+
set options such as the interval at which it checks files for changes, and
|
49
|
+
whether or not to force all the project's packages to be rebuild whenever a
|
50
|
+
change is made.
|
51
|
+
|
52
|
+
For a full list of options, run `jsrebuild --help`.
|
53
|
+
|
54
|
+
`jsrebuild` will happily run daemonised. To shut down the process, simply send
|
55
|
+
it `SIGHUP` and it will shut down the event loop and exit cleanly.
|
data/bin/jsrebuild
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.dirname(__FILE__) + '/../lib'
|
4
|
+
$:.unshift(lib) unless $:.include?(lib)
|
5
|
+
|
6
|
+
require 'oyster'
|
7
|
+
require 'jsrebuild'
|
8
|
+
|
9
|
+
spec = Oyster.spec do
|
10
|
+
name "jsrebuild -- dynamic rebuilder for JavaScript projects"
|
11
|
+
|
12
|
+
synopsis <<-EOS
|
13
|
+
jsrebuild [--force] [--interval TIME] [DIR]
|
14
|
+
EOS
|
15
|
+
|
16
|
+
description <<-EOS
|
17
|
+
Dynamically runs the Jake build tool to rebuild JavaScript
|
18
|
+
projects in development environments.
|
19
|
+
EOS
|
20
|
+
|
21
|
+
flag :force, :default => false,
|
22
|
+
:desc => "Force a rebuild of all files when any change is made"
|
23
|
+
|
24
|
+
float :interval, :default => 0.5,
|
25
|
+
:desc => <<-EOS
|
26
|
+
Set the frequency (in seconds) with which files are checked for
|
27
|
+
modifications.
|
28
|
+
EOS
|
29
|
+
|
30
|
+
author "Benedict Eastaugh <benedict@eastaugh.net>"
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
opts = spec.parse
|
35
|
+
rescue Oyster::HelpRendered
|
36
|
+
exit(true)
|
37
|
+
end
|
38
|
+
|
39
|
+
dir = File.expand_path(opts[:unclaimed].first || '.')
|
40
|
+
interval = opts[:interval]
|
41
|
+
jake_options = {
|
42
|
+
:force => opts[:force]
|
43
|
+
}
|
44
|
+
|
45
|
+
unless File.directory?(dir)
|
46
|
+
$stderr.puts "Directory \"#{dir}\" does not exist"
|
47
|
+
exit(false)
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
unless File.readable?(dir)
|
52
|
+
$stderr.puts "Directory \"#{dir}\" is not readable"
|
53
|
+
exit(false)
|
54
|
+
end
|
55
|
+
|
56
|
+
runner = JSRebuild::Runner.new(dir, interval, jake_options)
|
57
|
+
runner.run!
|
data/jsrebuild.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env gem build
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
lib = File.expand_path('../lib/', __FILE__)
|
5
|
+
$:.unshift lib unless $:.include?(lib)
|
6
|
+
|
7
|
+
require 'jsrebuild/version'
|
8
|
+
|
9
|
+
Gem::Specification.new do |gem|
|
10
|
+
gem.name = "jsrebuild"
|
11
|
+
gem.version = JSRebuild::VERSION
|
12
|
+
gem.platform = Gem::Platform::RUBY
|
13
|
+
|
14
|
+
gem.author = "Benedict Eastaugh"
|
15
|
+
gem.email = "benedict@eastaugh.net"
|
16
|
+
gem.homepage = "https://github.com/othermedia/jsrebuild"
|
17
|
+
|
18
|
+
gem.summary = "Dynamic rebuilder for JavaScript projects"
|
19
|
+
gem.description = "Dynamically runs the Jake build tool to rebuild JavaScript
|
20
|
+
projects in development environments.".sub(/\s+/, " ")
|
21
|
+
|
22
|
+
gem.license = "BSD"
|
23
|
+
|
24
|
+
gem.add_dependency "cool.io", ">= 1.1.0"
|
25
|
+
gem.add_dependency "eventful", ">= 1.0.0"
|
26
|
+
gem.add_dependency "jake", ">= 1.0.1"
|
27
|
+
gem.add_dependency "oyster", ">= 0.9.5"
|
28
|
+
|
29
|
+
gem.executables = ['jsrebuild']
|
30
|
+
gem.require_path = 'lib'
|
31
|
+
gem.files = `git ls-files`.split(/\s+/)
|
32
|
+
end
|
data/lib/jsrebuild.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
require 'coolio'
|
4
|
+
require 'eventful'
|
5
|
+
require 'jake'
|
6
|
+
|
7
|
+
module JSRebuild
|
8
|
+
CONFIG_FILE = Jake::CONFIG_FILE
|
9
|
+
HELPER_FILE = Jake::HELPER_FILE
|
10
|
+
|
11
|
+
LOG_FORMAT = "%-020s %-10s %-040s %-07s"
|
12
|
+
|
13
|
+
require 'jsrebuild/version'
|
14
|
+
require 'jsrebuild/config'
|
15
|
+
require 'jsrebuild/watcher'
|
16
|
+
require 'jsrebuild/runner'
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module JSRebuild
|
2
|
+
|
3
|
+
class Config < Jake::Build
|
4
|
+
def source_files
|
5
|
+
@packages.inject([]) { |files, (_, pkg)|
|
6
|
+
files.concat(pkg.files)
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def config_file
|
11
|
+
Jake.path(@dir, Jake::CONFIG_FILE)
|
12
|
+
end
|
13
|
+
|
14
|
+
def helper_file
|
15
|
+
Jake.path(@dir, Jake::HELPER_FILE)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module JSRebuild
|
2
|
+
class Runner
|
3
|
+
def initialize(dir, interval, jake_options)
|
4
|
+
@dir = Jake.path(dir || Dir.getwd)
|
5
|
+
@jake_options = jake_options
|
6
|
+
@config = load_config!
|
7
|
+
@watcher = Watcher.new(interval, @config)
|
8
|
+
end
|
9
|
+
|
10
|
+
def rebuild!
|
11
|
+
Jake::Build.delete_observers
|
12
|
+
|
13
|
+
build = Jake::Build.new(@dir, @jake_options)
|
14
|
+
|
15
|
+
build.on(:file_created) do |build, pkg, build_type, path|
|
16
|
+
size = (File.size(path) / 1024.0).ceil
|
17
|
+
$stderr.puts LOG_FORMAT % [pkg.name, build_type, path.gsub(@dir, ''), "#{ size } kB"]
|
18
|
+
end
|
19
|
+
|
20
|
+
build.on(:file_not_changed) do |build, pkg, build_type, path|
|
21
|
+
$stderr.puts LOG_FORMAT % [pkg.name, build_type, path.gsub(@dir, ''), 'UP-TO-DATE']
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
build.run!
|
26
|
+
rescue => err
|
27
|
+
$stderr.puts err.message + "\n" + (err.backtrace * "\n")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def load_config!
|
32
|
+
@config = Config.new(@dir, @jake_options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def run!
|
36
|
+
%w{HUP INT}.each do |sig|
|
37
|
+
Signal.trap(sig) { exit! }
|
38
|
+
end
|
39
|
+
|
40
|
+
@watcher.on :config_change do |w, path|
|
41
|
+
load_config!
|
42
|
+
rebuild!
|
43
|
+
end
|
44
|
+
|
45
|
+
@watcher.on :helper_change do |w, path|
|
46
|
+
load_config!
|
47
|
+
rebuild!
|
48
|
+
end
|
49
|
+
|
50
|
+
@watcher.on :source_change do |w, path|
|
51
|
+
rebuild!
|
52
|
+
end
|
53
|
+
|
54
|
+
rebuild!
|
55
|
+
|
56
|
+
@watcher.start
|
57
|
+
end
|
58
|
+
|
59
|
+
def exit!
|
60
|
+
@watcher.stop
|
61
|
+
exit(true)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module JSRebuild
|
2
|
+
# Every jsrebuild process has a Watcher, which keeps tabs on the config,
|
3
|
+
# helper and source files and notifies the application if any of them change.
|
4
|
+
class Watcher
|
5
|
+
include Eventful
|
6
|
+
|
7
|
+
# Set the interval at which files should be checked for changes, and pass
|
8
|
+
# in a JSRebuild::Config object which tells the watch which config, helper
|
9
|
+
# and source files it should watch.
|
10
|
+
def initialize(interval = 0.5, config)
|
11
|
+
@interval = interval
|
12
|
+
@config = config
|
13
|
+
@loop = nil
|
14
|
+
@watchers = nil
|
15
|
+
@config_watcher = nil
|
16
|
+
@helper_watcher = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# Start the watcher process.
|
20
|
+
def start
|
21
|
+
return unless @loop.nil?
|
22
|
+
|
23
|
+
config_file = @config.config_file
|
24
|
+
helper_file = @config.helper_file
|
25
|
+
|
26
|
+
@loop = Coolio::Loop.default
|
27
|
+
|
28
|
+
@config_watcher = FileWatcher.new(config_file, @interval)
|
29
|
+
@helper_watcher = FileWatcher.new(helper_file, @interval)
|
30
|
+
|
31
|
+
@config_watcher.on :change do
|
32
|
+
fire(:config_change, config_file)
|
33
|
+
reattach_source_watchers
|
34
|
+
end
|
35
|
+
|
36
|
+
@helper_watcher.on :change do
|
37
|
+
fire(:helper_change, helper_file)
|
38
|
+
reattach_source_watchers
|
39
|
+
end
|
40
|
+
|
41
|
+
@config_watcher.attach(@loop)
|
42
|
+
@helper_watcher.attach(@loop)
|
43
|
+
|
44
|
+
attach_source_watchers
|
45
|
+
|
46
|
+
@loop.run
|
47
|
+
end
|
48
|
+
|
49
|
+
# Detach all current source watchers and attach new ones.
|
50
|
+
#
|
51
|
+
# This is a simple and robust way of ensuring that when changes are made
|
52
|
+
# which change which files should be watched, only those files which should
|
53
|
+
# be watched are watched, and no others.
|
54
|
+
def reattach_source_watchers
|
55
|
+
detach_source_watchers
|
56
|
+
attach_source_watchers
|
57
|
+
end
|
58
|
+
|
59
|
+
# Attach a file watcher to each source file.
|
60
|
+
def attach_source_watchers
|
61
|
+
@source_watchers = {}
|
62
|
+
|
63
|
+
@config.source_files.each do |file|
|
64
|
+
watcher = FileWatcher.new(file, @interval)
|
65
|
+
@source_watchers[file] = watcher
|
66
|
+
|
67
|
+
watcher.on :change do
|
68
|
+
fire(:source_change, file)
|
69
|
+
end
|
70
|
+
|
71
|
+
watcher.attach(@loop)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Detach all current source watchers.
|
76
|
+
def detach_source_watchers
|
77
|
+
unless @source_watchers.nil? || @source_watchers.empty?
|
78
|
+
@source_watchers.each do |file, watcher|
|
79
|
+
watcher.detach
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Detach all watchers and stop the event loop.
|
85
|
+
def stop
|
86
|
+
detach_source_watchers
|
87
|
+
|
88
|
+
@config_watcher.detach
|
89
|
+
@helper_watcher.detach
|
90
|
+
|
91
|
+
@loop.stop
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# The FileWatcher class is a small extension to the Coolio::StatWatcher class
|
96
|
+
# which encapsulates one further piece of information, the last time the
|
97
|
+
# watched file was changed.
|
98
|
+
#
|
99
|
+
# When the watched file changes, FileWatcher objects notify any observers
|
100
|
+
# only when the file has been modified since it was last checked.
|
101
|
+
class FileWatcher < Coolio::StatWatcher
|
102
|
+
include Eventful
|
103
|
+
|
104
|
+
# Notify any observers if either the file no longer exists, or if the file
|
105
|
+
# has been modified since it was last checked.
|
106
|
+
def on_change(prev, current)
|
107
|
+
fire(:change) and return unless File.exists?(path)
|
108
|
+
|
109
|
+
fire(:change) if current.ctime > prev.ctime
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/test/Jakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
$stderr.puts "Jake helper file running..."
|
data/test/jake.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
var Fake = {};
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jsrebuild
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Benedict Eastaugh
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-12 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: cool.io
|
16
|
+
requirement: &2152045800 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2152045800
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: eventful
|
27
|
+
requirement: &2152045300 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.0.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2152045300
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: jake
|
38
|
+
requirement: &2152044840 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.1
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2152044840
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: oyster
|
49
|
+
requirement: &2152044380 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.5
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152044380
|
58
|
+
description: ! "Dynamically runs the Jake build tool to rebuild JavaScript\n projects
|
59
|
+
in development environments."
|
60
|
+
email: benedict@eastaugh.net
|
61
|
+
executables:
|
62
|
+
- jsrebuild
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- .gitignore
|
67
|
+
- Gemfile
|
68
|
+
- History.txt
|
69
|
+
- LICENSE
|
70
|
+
- README.md
|
71
|
+
- bin/jsrebuild
|
72
|
+
- jsrebuild.gemspec
|
73
|
+
- lib/jsrebuild.rb
|
74
|
+
- lib/jsrebuild/config.rb
|
75
|
+
- lib/jsrebuild/runner.rb
|
76
|
+
- lib/jsrebuild/version.rb
|
77
|
+
- lib/jsrebuild/watcher.rb
|
78
|
+
- test/Jakefile
|
79
|
+
- test/jake.yml
|
80
|
+
- test/source/fake_core.js
|
81
|
+
- test/source/fake_ui.js
|
82
|
+
homepage: https://github.com/othermedia/jsrebuild
|
83
|
+
licenses:
|
84
|
+
- BSD
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 1.8.7
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Dynamic rebuilder for JavaScript projects
|
107
|
+
test_files: []
|