ki-repo 0.1.1 → 0.1.2
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.
- checksums.yaml +15 -0
- data/LICENSE.txt +1 -1
- data/README.md +21 -0
- data/VERSION +1 -1
- data/bin/ki +1 -1
- data/docs/backlog.md +10 -10
- data/docs/development.md +3 -1
- data/docs/ki_commands.md +35 -6
- data/docs/repository_basics.md +12 -1
- data/docs/writing_extensions.md +25 -7
- data/lib/cmd/cmd.rb +69 -54
- data/lib/cmd/user_pref_cmd.rb +47 -37
- data/lib/cmd/version_cmd.rb +116 -113
- data/lib/data_access/repository_finder.rb +1 -1
- data/lib/data_access/repository_info.rb +1 -1
- data/lib/data_access/version_helpers.rb +11 -11
- data/lib/data_access/version_iterators.rb +6 -6
- data/lib/data_access/version_operations.rb +1 -1
- data/lib/data_storage/dir_base.rb +20 -18
- data/lib/data_storage/ki_home.rb +1 -1
- data/lib/data_storage/ki_json.rb +4 -2
- data/lib/data_storage/repository.rb +1 -1
- data/lib/data_storage/version_metadata.rb +54 -39
- data/lib/ki_repo_all.rb +7 -1
- data/lib/util/attr_chain.rb +2 -2
- data/lib/util/exception_catcher.rb +1 -1
- data/lib/util/hash.rb +1 -1
- data/lib/util/hash_cache.rb +1 -1
- data/lib/util/hash_log.rb +93 -0
- data/lib/util/ruby_extensions.rb +58 -21
- data/lib/util/service_registry.rb +1 -1
- data/lib/util/shell.rb +96 -0
- data/lib/util/simple_optparse.rb +6 -4
- data/lib/util/test.rb +13 -1
- data/lib/web/default_rack_handler.rb +43 -0
- data/lib/web/rack_cmd.rb +161 -0
- data/lib/web/test_browser.rb +69 -0
- metadata +80 -24
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -104,14 +104,14 @@ module Ki
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def import_from_metadata(metadata, source=nil)
|
107
|
-
if
|
107
|
+
if specific_version_id && create_new_version
|
108
108
|
raise "Can't define both specific_version_id '#{specific_version_id}' and create_new_version '#{create_new_version}'!"
|
109
109
|
end
|
110
110
|
|
111
|
-
if
|
112
|
-
version_id =
|
113
|
-
elsif
|
114
|
-
component_id =
|
111
|
+
if specific_version_id
|
112
|
+
version_id = specific_version_id
|
113
|
+
elsif create_new_version
|
114
|
+
component_id = create_new_version
|
115
115
|
version = finder.version(component_id)
|
116
116
|
if version
|
117
117
|
id = version.version_id.split("/").last
|
@@ -140,7 +140,7 @@ module Ki
|
|
140
140
|
metadata_dir.metadata.cached_data = metadata.cached_data
|
141
141
|
metadata_dir.metadata.version_id = version_id
|
142
142
|
metadata_dir.metadata.save
|
143
|
-
if
|
143
|
+
if move_files
|
144
144
|
FileUtils.rm(metadata.path)
|
145
145
|
end
|
146
146
|
source_dirs = []
|
@@ -158,7 +158,7 @@ module Ki
|
|
158
158
|
|
159
159
|
|
160
160
|
def delete_empty_source_dirs(source, source_dirs)
|
161
|
-
if
|
161
|
+
if move_files
|
162
162
|
expanded_source_dirs = {}
|
163
163
|
source_dirs.each do |d|
|
164
164
|
dir_entries(d).each do |expanded|
|
@@ -179,7 +179,7 @@ module Ki
|
|
179
179
|
arr = str.split("/")
|
180
180
|
ret = []
|
181
181
|
c = arr.size
|
182
|
-
while
|
182
|
+
while c > 0
|
183
183
|
ret << File.join(arr[0..c])
|
184
184
|
c-=1
|
185
185
|
end
|
@@ -187,7 +187,7 @@ module Ki
|
|
187
187
|
end
|
188
188
|
|
189
189
|
def to_repo(src, dest)
|
190
|
-
if
|
190
|
+
if move_files
|
191
191
|
FileUtils.mv(src, dest)
|
192
192
|
else
|
193
193
|
FileUtils.cp(src, dest)
|
@@ -223,7 +223,7 @@ module Ki
|
|
223
223
|
if dir != "."
|
224
224
|
FileUtils.mkdir_p File.join(out, dir)
|
225
225
|
end
|
226
|
-
if
|
226
|
+
if copy
|
227
227
|
FileUtils.cp(full_path, File.join(out, file_path))
|
228
228
|
else
|
229
229
|
FileUtils.ln_sf(full_path, File.join(out, file_path))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -25,7 +25,7 @@ module Ki
|
|
25
25
|
attr_chain :finder, -> { version.component.finder }
|
26
26
|
attr_chain :block
|
27
27
|
attr_chain :internals
|
28
|
-
attr_chain :exclude_dependencies, -> { [] }, :convert => lambda { |list| Array
|
28
|
+
attr_chain :exclude_dependencies, -> { [] }, :convert => lambda { |list| Array(list).map { |s| /#{s}/ } }
|
29
29
|
|
30
30
|
def iterate_versions(&block)
|
31
31
|
start_iteration do |version_iterator|
|
@@ -80,10 +80,10 @@ module Ki
|
|
80
80
|
end
|
81
81
|
|
82
82
|
class FileFinder < VersionIterator
|
83
|
-
attr_chain :files, -> { [] }, :convert => lambda { |list| Array
|
84
|
-
attr_chain :exclude_files, -> { [] }, :convert => lambda { |list| Array
|
85
|
-
attr_chain :tags, -> { [] }, :convert => lambda { |list| Array
|
86
|
-
attr_chain :exclude_tags, -> { [] }, :convert => lambda { |list| Array
|
83
|
+
attr_chain :files, -> { [] }, :convert => lambda { |list| Array(list).map { |s| FileRegexp.matcher(s) } }
|
84
|
+
attr_chain :exclude_files, -> { [] }, :convert => lambda { |list| Array(list).map { |s| FileRegexp.matcher(s) } }
|
85
|
+
attr_chain :tags, -> { [] }, :convert => lambda { |list| Array(list)}
|
86
|
+
attr_chain :exclude_tags, -> { [] }, :convert => lambda { |list| Array(list)}
|
87
87
|
|
88
88
|
def file_map
|
89
89
|
start_iteration do |ver_iterator|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -15,9 +15,25 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
17
|
module Ki
|
18
|
-
|
18
|
+
|
19
|
+
class DirectoryBase
|
19
20
|
attr_chain :parent, :require
|
20
21
|
|
22
|
+
def initialize(path)
|
23
|
+
init_from_path(path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find!(path, *locations)
|
27
|
+
locations.each do |loc|
|
28
|
+
dest = loc.go(path)
|
29
|
+
if dest.exists?
|
30
|
+
return dest
|
31
|
+
end
|
32
|
+
end
|
33
|
+
raise "Could not find '#{path}' from '#{locations.map { |l| l.path }.join("', '")}'"
|
34
|
+
end
|
35
|
+
|
36
|
+
|
21
37
|
def init_from_path(path)
|
22
38
|
@path = path
|
23
39
|
end
|
@@ -84,23 +100,9 @@ module Ki
|
|
84
100
|
def child(name)
|
85
101
|
DirectoryBase.new(name)
|
86
102
|
end
|
87
|
-
end
|
88
|
-
|
89
|
-
class DirectoryBase
|
90
|
-
include DirectoryBaseModule
|
91
|
-
|
92
|
-
def initialize(path)
|
93
|
-
init_from_path(path)
|
94
|
-
end
|
95
103
|
|
96
|
-
def
|
97
|
-
|
98
|
-
dest = loc.go(path)
|
99
|
-
if dest.exists?
|
100
|
-
return dest
|
101
|
-
end
|
102
|
-
end
|
103
|
-
raise "Could not find '#{path}' from '#{locations.map { |l| l.path }.join("', '")}'"
|
104
|
+
def empty?(*sub_path)
|
105
|
+
Dir.entries(go(*sub_path).path).size == 2
|
104
106
|
end
|
105
107
|
end
|
106
108
|
end
|
data/lib/data_storage/ki_home.rb
CHANGED
data/lib/data_storage/ki_json.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -71,7 +71,9 @@ module Ki
|
|
71
71
|
|
72
72
|
def add_item(obj)
|
73
73
|
edit_data do
|
74
|
-
|
74
|
+
if !@cached_data.include?(obj)
|
75
|
+
@cached_data << obj
|
76
|
+
end
|
75
77
|
end
|
76
78
|
create_list_item(obj)
|
77
79
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -29,16 +29,6 @@ module Ki
|
|
29
29
|
attr_chain :operations, -> { Array.new }, :accessor => CachedData
|
30
30
|
attr_chain :dependencies, -> { Array.new }, :accessor => CachedData
|
31
31
|
|
32
|
-
def add_file_info(name, size, *args)
|
33
|
-
extra = (args.select { |arg| arg.kind_of?(Hash) }.size!(0..1).first or {})
|
34
|
-
tags = (args - [extra]).flatten.uniq
|
35
|
-
file_hash = {"path" => name, "size" => size}.merge(extra)
|
36
|
-
if tags.size > 0
|
37
|
-
file_hash["tags"]=tags
|
38
|
-
end
|
39
|
-
files << file_hash
|
40
|
-
end
|
41
|
-
|
42
32
|
# Comma separated list of dependency arguments
|
43
33
|
# * dependency parameters can be given in the hash
|
44
34
|
# TODO: version_id should be resolved through Version
|
@@ -58,41 +48,27 @@ module Ki
|
|
58
48
|
operations << args
|
59
49
|
end
|
60
50
|
|
61
|
-
def VersionMetadataFile.calculate_hashes(full_path, digester_ids)
|
62
|
-
digesters = {}
|
63
|
-
digester_ids.each do |h|
|
64
|
-
digesters[h] = KiCommand::KiExtensions.find!(File.join("/hashing", h)).digest
|
65
|
-
end
|
66
|
-
algos = digesters.values
|
67
|
-
File.open(full_path, "r") do |io|
|
68
|
-
while (!io.eof)
|
69
|
-
buf = io.readpartial(1024)
|
70
|
-
algos.each do |digester|
|
71
|
-
digester.update(buf)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
digesters.each_pair do |h, digester|
|
76
|
-
digesters[h]=digester.hexdigest
|
77
|
-
end
|
78
|
-
digesters
|
79
|
-
end
|
80
|
-
|
81
51
|
# Processes all files from source that match patterns and for each file calculates hashes and stores tags based on default_parameters
|
82
52
|
def add_files(source, patterns, default_parameters={})
|
83
|
-
files_or_dirs = Array
|
53
|
+
files_or_dirs = Array(patterns).map do |pattern|
|
84
54
|
Dir.glob(File.join(source, pattern))
|
85
55
|
end.flatten
|
86
56
|
|
87
|
-
files =
|
88
|
-
|
89
|
-
|
57
|
+
files = []
|
58
|
+
|
59
|
+
files_or_dirs.each do |file_or_dir|
|
60
|
+
if File.file?(file_or_dir)
|
61
|
+
files << file_or_dir
|
90
62
|
else
|
91
|
-
file_or_dir
|
63
|
+
Dir.glob(File.join(file_or_dir, "**/*")).each do |file|
|
64
|
+
if File.file?(file)
|
65
|
+
files << file
|
66
|
+
end
|
67
|
+
end
|
92
68
|
end
|
93
|
-
end
|
69
|
+
end
|
94
70
|
|
95
|
-
files.each do |file|
|
71
|
+
files.sort.each do |file|
|
96
72
|
add_file(source, file, default_parameters)
|
97
73
|
end
|
98
74
|
self
|
@@ -106,7 +82,7 @@ module Ki
|
|
106
82
|
extra["executable"]=true
|
107
83
|
end
|
108
84
|
if parameters["tags"]
|
109
|
-
tags = Array
|
85
|
+
tags = Array(parameters["tags"])
|
110
86
|
if tags && tags.size > 0
|
111
87
|
extra["tags"]= tags
|
112
88
|
end
|
@@ -119,6 +95,45 @@ module Ki
|
|
119
95
|
end
|
120
96
|
add_file_info(full_path[root.size+1..-1], size, extra)
|
121
97
|
end
|
98
|
+
|
99
|
+
def add_file_info(name, size, *args)
|
100
|
+
extra = (args.select { |arg| arg.kind_of?(Hash) }.size!(0..1).first or {})
|
101
|
+
tags = (args - [extra]).flatten.uniq
|
102
|
+
file_hash = {"path" => name, "size" => size}.merge(extra)
|
103
|
+
if tags.size > 0
|
104
|
+
file_hash["tags"]=tags
|
105
|
+
end
|
106
|
+
files.each do |f|
|
107
|
+
if f["path"] == name
|
108
|
+
if f == file_hash
|
109
|
+
return
|
110
|
+
else
|
111
|
+
raise "'#{name}' has already been added to version, but with different attributes:\n- old: #{f.inspect}\n- new: #{file_hash.inspect}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
files << file_hash
|
116
|
+
end
|
117
|
+
|
118
|
+
def VersionMetadataFile.calculate_hashes(full_path, digester_ids)
|
119
|
+
digesters = {}
|
120
|
+
digester_ids.each do |h|
|
121
|
+
digesters[h] = KiCommand::KiExtensions.find!(File.join("/hashing", h)).digest
|
122
|
+
end
|
123
|
+
algos = digesters.values
|
124
|
+
File.open(full_path, "r") do |io|
|
125
|
+
while (!io.eof)
|
126
|
+
buf = io.readpartial(1024)
|
127
|
+
algos.each do |digester|
|
128
|
+
digester.update(buf)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
digesters.each_pair do |h, digester|
|
133
|
+
digesters[h]=digester.hexdigest
|
134
|
+
end
|
135
|
+
digesters
|
136
|
+
end
|
122
137
|
end
|
123
138
|
|
124
139
|
module DependencyMethods
|
data/lib/ki_repo_all.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -23,7 +23,9 @@ require_relative 'util/test'
|
|
23
23
|
require_relative 'util/service_registry'
|
24
24
|
require_relative 'util/hash'
|
25
25
|
require_relative 'util/hash_cache'
|
26
|
+
require_relative 'util/hash_log'
|
26
27
|
require_relative 'util/simple_optparse'
|
28
|
+
require_relative 'util/shell'
|
27
29
|
|
28
30
|
require_relative 'data_storage/dir_base'
|
29
31
|
require_relative 'data_storage/ki_json'
|
@@ -40,3 +42,7 @@ require_relative 'data_access/version_iterators'
|
|
40
42
|
require_relative 'cmd/cmd'
|
41
43
|
require_relative 'cmd/version_cmd'
|
42
44
|
require_relative 'cmd/user_pref_cmd'
|
45
|
+
|
46
|
+
require_relative 'web/default_rack_handler'
|
47
|
+
require_relative 'web/rack_cmd'
|
48
|
+
require_relative 'web/test_browser'
|
data/lib/util/attr_chain.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
# Copyright 2012 Mikko Apo
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
@@ -45,7 +45,7 @@
|
|
45
45
|
# * :default makes it easy to isolate functionality to a default value while still making it easy to override the default behaviour
|
46
46
|
# * :default adds easy lazy evalution and memoization to the attribute, default value is evaluated only if needed
|
47
47
|
# * Testing becomes easier when objects have more exposed fields
|
48
|
-
# * :require converts tricky nil exceptions in to useful errors. Instead of the "undefined method
|
48
|
+
# * :require converts tricky nil exceptions in to useful errors. Instead of the "undefined method 'bar' for nil:NilClass" you get a good error message that states which field was not defined
|
49
49
|
# foo.name.bar # if name has not been defined, raises "'name' has not been set" exception
|
50
50
|
# * :immutable, :valid and :convert make complex validations and converts easy
|
51
51
|
#
|
data/lib/util/hash.rb
CHANGED
data/lib/util/hash_cache.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# Copyright 2012-2013 Mikko Apo
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module Ki
|
18
|
+
# Generate hash object based log entries.
|
19
|
+
# @see log
|
20
|
+
module HashLog
|
21
|
+
HashLogThreadCurrentKey = :hash_log
|
22
|
+
HashLogMutex = Mutex.new
|
23
|
+
|
24
|
+
# Create a hash log entry or return current hash log entry
|
25
|
+
# * Supports hierarchic logs, where log entry can contain any number of sub entries
|
26
|
+
# * Supports parallel execution, threads can log in to one log structure
|
27
|
+
# * Logs start and stop time of execution
|
28
|
+
#
|
29
|
+
# Hierarchic logging works by keeping a stack of log entries in Thread local store
|
30
|
+
#
|
31
|
+
# @see set_hash_log_root_for_thread
|
32
|
+
# @see hash_log_current
|
33
|
+
def log(*args, &block)
|
34
|
+
current_log_entry = hash_log_current
|
35
|
+
# return
|
36
|
+
if args.empty? && block.nil?
|
37
|
+
current_log_entry
|
38
|
+
else
|
39
|
+
new_entry = {"start" => Time.now}
|
40
|
+
if args.first.kind_of?(String)
|
41
|
+
new_entry["name"] = args.delete_at(0)
|
42
|
+
end
|
43
|
+
if args.first.kind_of?(Hash)
|
44
|
+
new_entry.merge!(args.first)
|
45
|
+
end
|
46
|
+
log_list = nil
|
47
|
+
if current_log_entry
|
48
|
+
# there is current log entry, create a new sub log entry
|
49
|
+
HashLogMutex.synchronize do
|
50
|
+
log_list = current_log_entry["logs"] ||= []
|
51
|
+
end
|
52
|
+
else
|
53
|
+
# append new_entry to end of log list
|
54
|
+
log_list = Thread.current[HashLogThreadCurrentKey]
|
55
|
+
end
|
56
|
+
HashLogMutex.synchronize do
|
57
|
+
log_list << new_entry
|
58
|
+
end
|
59
|
+
if block
|
60
|
+
HashLogMutex.synchronize do
|
61
|
+
Thread.current[HashLogThreadCurrentKey] << new_entry
|
62
|
+
end
|
63
|
+
begin
|
64
|
+
block.call new_entry
|
65
|
+
rescue Exception => e
|
66
|
+
new_entry["exception"] = e.message
|
67
|
+
new_entry["backtrace"] = e.backtrace.join("\n")
|
68
|
+
raise
|
69
|
+
ensure
|
70
|
+
HashLogMutex.synchronize do
|
71
|
+
Thread.current[HashLogThreadCurrentKey].delete(new_entry)
|
72
|
+
end
|
73
|
+
new_entry["end"] = Time.now
|
74
|
+
end
|
75
|
+
else
|
76
|
+
new_entry
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_hash_log_root_for_thread(root)
|
82
|
+
HashLogMutex.synchronize do
|
83
|
+
(Thread.current[HashLogThreadCurrentKey] ||= []) << root
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def hash_log_current
|
88
|
+
HashLogMutex.synchronize do
|
89
|
+
(Thread.current[HashLogThreadCurrentKey] ||= []).last
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|