license_header 0.0.1

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/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # LicenseHeader
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'license_header'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install license_header
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'license_header'
4
+ require 'optparse'
5
+ require 'highline/import'
6
+
7
+ command = nil
8
+ options = { :exceptions => [] }
9
+
10
+ @prompt = true
11
+ def getYyn(text)
12
+ if @prompt
13
+ response = ask("#{text} (Y/y/n) ") { |q|
14
+ q.overwrite = true
15
+ q.echo = true
16
+ q.character = true
17
+ q.validate { |r| r =~ /^[Yyn]$/ }
18
+ }
19
+ if response == 'Y'
20
+ @prompt = false
21
+ end
22
+ return response.downcase == 'y'
23
+ else
24
+ return true
25
+ end
26
+ end
27
+
28
+ opts = OptionParser.new do |opts|
29
+ opts.banner = "Usage: #{File.basename $0} <action> [options] <filespec>"
30
+
31
+ opts.separator 'Actions:'
32
+
33
+ opts.on('-a', '--audit', "Print a list of files needing license updates") do
34
+ command = :audit
35
+ end
36
+
37
+ opts.on('-u', '--update', "Update files requiring license headers") do
38
+ command = :update
39
+ end
40
+
41
+ opts.on('-r', '--remove', "Remove license headers from files") do
42
+ command = :remove
43
+ end
44
+
45
+ opts.separator 'Common options:'
46
+
47
+ opts.on('-f FILE', '--header-file=FILE', "File containing header text") do |arg|
48
+ options[:header] = arg
49
+ end
50
+
51
+ opts.on('-x MASK', '--exclude=MASK', "Exclude pattern") do |arg|
52
+ pattern = Regexp.escape(arg).gsub('\*','.*?')
53
+ re = /^#{pattern}$/i
54
+ options[:exceptions] << re
55
+ end
56
+
57
+ opts.on('-y', '--yes', "Assume yes reponses to all prompts") do
58
+ @prompt = false
59
+ end
60
+
61
+ opts.on('-v', '--verbose', "Run verbosely") do
62
+ options[:verbose] = true
63
+ end
64
+
65
+ opts.on_tail('-h', '--help', "Show this message") do
66
+ puts opts
67
+ exit
68
+ end
69
+ end
70
+ opts.parse!
71
+
72
+ if command.nil? or options[:header].nil? or ARGV.empty?
73
+ puts opts
74
+ exit
75
+ end
76
+
77
+ targets = ARGV.collect do |spec|
78
+ File.directory?(spec) ? File.join(spec,"**","*") : spec
79
+ end
80
+
81
+ auditor = LicenseHeader::Auditor.new(options)
82
+ files = auditor.audit(*targets)
83
+ invalid = (files[:missing]+files[:invalid]).sort
84
+ present = (files[:present]+files[:valid]).sort
85
+ case command
86
+ when :audit
87
+ $stderr.puts "#{files[:valid].length} files have correct headers"
88
+ $stderr.puts files[:valid].join("\n") if options[:verbose]
89
+ $stderr.puts "#{files[:missing].length} files have missing headers"
90
+ $stderr.puts files[:missing].join("\n") if options[:verbose]
91
+ $stderr.puts "#{files[:invalid].length} files have invalid headers"
92
+ $stderr.puts files[:invalid].join("\n") if options[:verbose]
93
+ when :update
94
+ $stderr.puts "#{invalid.length} files have missing or incorrect headers"
95
+ auditor.process_files(:update, * invalid) do |file, format|
96
+ response = getYyn("Update header in #{file}?")
97
+ $stderr.puts "Updating #{file}..." if response
98
+ response
99
+ end
100
+ when :remove
101
+ $stderr.puts "#{present.length} files have headers"
102
+ auditor.process_files(:remove, *present) do |file, format|
103
+ response = getYyn("Remove header from #{file}?")
104
+ $stderr.puts "Cleaning up #{file}..." if response
105
+ response
106
+ end
107
+ end
@@ -0,0 +1,142 @@
1
+ require 'fileutils'
2
+
3
+ # Module to assist in making sure that all files have the right license
4
+ # block as a header.
5
+
6
+ module LicenseHeader
7
+ # For each language you can define three variables
8
+ #
9
+ # :pre will be prepended to the header
10
+ # :each will be prepended to each line of the header
11
+ # :post will be appended to the end of the file
12
+ #
13
+ # Only :each is required; if the other two are not provided they will be
14
+ # ignored
15
+ LANGUAGE_SYNTAX = {
16
+ :css => { :pre => '/* ', :each => ' * ', :post => '*/', :exts => %w(.css .scss) },
17
+ :erb => { :pre => '<%#', :each => '', :post => '%>', :exts => %w(.erb) },
18
+ :haml => { :pre => '-#', :each => ' ', :exts => %w(.haml) },
19
+ :html => { :pre => '<!--', :each => '', :post => '-->', :exts => %w(.html) },
20
+ :javascript => { :pre => '/* ', :each => ' * ', :post => '*/', :exts => %w(.js .json) },
21
+ :ruby => { :each => '# ', :exts => %w(.rb .rake .coffee) },
22
+ }
23
+
24
+ class Auditor
25
+ attr_accessor :exceptions, :header, :verbose
26
+
27
+ # Should set some sensible defaults here for license location, file
28
+ # mappings, etc
29
+ def initialize(configuration)
30
+ @verbose = configuration[:verbose]
31
+ @header = configuration[:header]
32
+ @exceptions = configuration[:exceptions]
33
+ initialize_headers
34
+ end
35
+
36
+ # Create a list of all files grouped by type and return the map
37
+ def audit(*patterns)
38
+ result = Hash.new { |h,k| h[k] = [] }
39
+
40
+ Dir.glob(patterns).each do |entry|
41
+ # Skip directories and files that match the exceptions
42
+ next if File.directory?(entry)
43
+ if @exceptions.any? { |ex| ex.match(entry) }
44
+ $stderr.puts "Skipping #{entry}" if @verbose
45
+ next
46
+ end
47
+
48
+ # Now to get down to business
49
+ format = determine_format(entry)
50
+ result[evaluate_header(entry, format)] << entry
51
+ end
52
+
53
+ return result
54
+ end
55
+
56
+ def evaluate_header(path, format)
57
+ if format.nil? or format[:header].nil?
58
+ :not_applicable
59
+ else
60
+ file_content = read_file(path)
61
+ header_content = format[:header]
62
+ index = file_content.find_index { |l| l =~ /--- [E]ND AVALON LICENSE BLOCK ---/ }
63
+ if index.nil?
64
+ :missing
65
+ else
66
+ file_heading = file_content[0, header_content.size]
67
+ if file_heading.eql? header_content
68
+ :valid
69
+ else
70
+ :present
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ def process_files(action, *files)
77
+ files.each do |file|
78
+ format = determine_format(file)
79
+ source_file = read_file(file)
80
+ confirm = block_given? ? yield(file) : true
81
+ if confirm and self.send(:"#{action.to_s}_license!", source_file, format)
82
+ write_file(file, source_file)
83
+ end
84
+ end
85
+ end
86
+
87
+ def update_license!(source_file, format)
88
+ remove_license!(source_file, format)
89
+ header_content = format[:header]
90
+ header_content.reverse.each { |line| source_file.insert(0, line) }
91
+ return true
92
+ end
93
+
94
+ def remove_license!(source_file, format)
95
+ end_of_license = source_file.find_index { |l| l =~ /--- [E]ND AVALON LICENSE BLOCK ---/ }
96
+ if end_of_license.nil?
97
+ return false
98
+ else
99
+ extra_lines = format[:post].nil? ? 1 : 2
100
+ source_file.shift(end_of_license+extra_lines+1)
101
+ return true
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def determine_format(file)
108
+ @headers.values.find { |syntax| syntax[:exts].include?(File.extname(file)) }
109
+ end
110
+
111
+ def read_file(file)
112
+ File.read(file).chomp.split(/\n/)
113
+ end
114
+
115
+ def write_file(file, content)
116
+ File.open("#{file}.tmp", "w") { |tmpfile| tmpfile.puts(content.join("\n")) }
117
+ FileUtils.rm(file)
118
+ FileUtils.mv("#{file}.tmp", file)
119
+ end
120
+
121
+ # Here we need to take the stock header and create two different versions -
122
+ # one for Ruby based content using the # notation and another for
123
+ # Javascript that uses /* */ syntax
124
+ def initialize_headers
125
+ @headers = LANGUAGE_SYNTAX.clone
126
+ base = File.read(@header)
127
+ # Break each line down so we can do easy manipulation to create our new
128
+ # versions
129
+ license_terms = base.split(/\n/)
130
+
131
+ @headers.each_pair do |lang,syntax|
132
+ syntax[:header] = []
133
+ syntax[:header] << syntax[:pre] unless syntax[:pre].nil?
134
+ syntax[:header] << "#{syntax[:each]} --- BEGIN AVALON LICENSE BLOCK ---"
135
+ syntax[:header] += license_terms.collect {|line| syntax[:each] + line }
136
+ syntax[:header] << "#{syntax[:each]} --- #{'E'}ND AVALON LICENSE BLOCK ---"
137
+ syntax[:header] << syntax[:post] unless syntax[:post].nil?
138
+ syntax[:header] << ""
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,3 @@
1
+ module LicenseHeader
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "license_header/version"
2
+ require "license_header/auditor"
3
+
4
+ module LicenseHeader
5
+ # Your code goes here...
6
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: license_header
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nathan Rogers
9
+ - Michael Klein
10
+ - Chris Colvard
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2013-04-18 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: highline
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: bundler
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ - !ruby/object:Gem::Dependency
49
+ name: rake
50
+ requirement: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ description: License header block auditing/updating
65
+ email:
66
+ - rogersna@indiana.edu
67
+ executables:
68
+ - license_header
69
+ extensions: []
70
+ extra_rdoc_files: []
71
+ files:
72
+ - lib/license_header/auditor.rb
73
+ - lib/license_header/version.rb
74
+ - lib/license_header.rb
75
+ - bin/license_header
76
+ - README.md
77
+ homepage:
78
+ licenses: []
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ segments:
90
+ - 0
91
+ hash: 3735959797291095628
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ segments:
99
+ - 0
100
+ hash: 3735959797291095628
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 1.8.23
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: This gem will assist in making sure that all files have the right license
107
+ block as a header.
108
+ test_files: []