jsrebuild 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|