Rewrite in ruby.
This commit is contained in:
parent
4c4f0e1ddc
commit
f90bbee818
11 changed files with 514 additions and 164 deletions
0
Gemfile
Normal file
0
Gemfile
Normal file
5
Kookfile
Normal file
5
Kookfile
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
:project: kook2
|
||||
:description:
|
||||
:path: /home/warbrain/src/_Glenux/kotam
|
||||
:views: []
|
23
bin/kook
Executable file
23
bin/kook
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env ruby
|
||||
# vim: set syntax=ruby:
|
||||
|
||||
#require 'bundler/setup'
|
||||
require 'yaml'
|
||||
require 'singleton'
|
||||
require 'pry'
|
||||
require 'colorize'
|
||||
require 'pp'
|
||||
|
||||
DATA_DIR = File.expand_path(
|
||||
File.join(File.dirname(__FILE__),'..')
|
||||
)
|
||||
|
||||
VERSION = "0.3"
|
||||
|
||||
$:.insert 0, File.join(DATA_DIR, 'lib')
|
||||
|
||||
require 'thor'
|
||||
require 'kook'
|
||||
|
||||
Kook::CLI::Main.start(ARGV)
|
||||
|
164
bin/kook.rb
164
bin/kook.rb
|
@ -1,164 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'singleton'
|
||||
require 'yaml'
|
||||
require 'pp'
|
||||
|
||||
module Kook
|
||||
class Project
|
||||
attr_reader :name, :path
|
||||
attr_accessor :description
|
||||
PROJECT_NAME_MIN_SIZE = 4
|
||||
PROJECT_NAME_MAX_SIZE = 12
|
||||
|
||||
def initialize project_name
|
||||
self.class.validate_name project_name
|
||||
@name = project_name
|
||||
@description = nil
|
||||
@path = nil
|
||||
@views = {}
|
||||
end
|
||||
|
||||
def path= path
|
||||
# FIXME: validate current path exists
|
||||
#
|
||||
if not (File.exist? path and File.directory? path) then
|
||||
raise "PathDoesNotExist #{path}"
|
||||
end
|
||||
@path = path
|
||||
end
|
||||
|
||||
def add_view view
|
||||
raise "ExistingView #{view.name}" if @views.has_key? view.name
|
||||
@views[view.name] = view
|
||||
end
|
||||
|
||||
def remove_view view_name
|
||||
View.validate_name view_name
|
||||
return @view.delete(view_name)
|
||||
end
|
||||
|
||||
def to_hash
|
||||
return {
|
||||
project: @name,
|
||||
description: @description,
|
||||
path: @path,
|
||||
views: @views.values.map{ |v| v.to_hash }
|
||||
}
|
||||
end
|
||||
|
||||
def from_hash project_hash
|
||||
@name = project_hash[:project]
|
||||
@description = project_hash[:description]
|
||||
@path = project_hash[:path]
|
||||
project_hash[:views].each do |hash_view|
|
||||
view = View.new do |v|
|
||||
v.from_hash hash_view
|
||||
end
|
||||
add_view view
|
||||
end
|
||||
end
|
||||
|
||||
def self.validate_name name
|
||||
raise "TooShortProjectIdentifier" if name.size < Project::PROJECT_NAME_MIN_SIZE
|
||||
raise "TooLongProjectIdentifier" if name.size > Project::PROJECT_NAME_MAX_SIZE
|
||||
if not name =~ /^\w+$/ then
|
||||
raise "BadProjectIdentifier #{name}"
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
class View
|
||||
attr_reader :name, :path
|
||||
attr_accessor :description
|
||||
VIEW_NAME_MIN_SIZE = 4
|
||||
VIEW_NAME_MAX_SIZE = 12
|
||||
|
||||
def initialize name
|
||||
self.class.validate_name name
|
||||
@name = name
|
||||
@path = nil
|
||||
@commands = {}
|
||||
end
|
||||
|
||||
def self.validate_name name
|
||||
raise "TooShortViewIdentifier" if name.size < View::VIEW_NAME_MIN_SIZE
|
||||
raise "TooLongViewIdentifier" if name.size > View::VIEW_NAME_MAX_SIZE
|
||||
if not name =~ /^[\w-]+$/ then
|
||||
raise "BadViewIdentifier #{name}"
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def to_hash
|
||||
return {
|
||||
view: @name,
|
||||
path: @path,
|
||||
commands: @commands.values
|
||||
}
|
||||
end
|
||||
|
||||
def from_hash view_hash
|
||||
@name = view_hash[:view]
|
||||
@path = view_hash[:path]
|
||||
@commands = view_hash[:commands]
|
||||
end
|
||||
end
|
||||
|
||||
class Command
|
||||
end
|
||||
|
||||
class Config
|
||||
include Singleton
|
||||
|
||||
def create_project project_name
|
||||
raise "ExistingProject" if @projects.has_key? project_name
|
||||
|
||||
@projects[project_name] = Project.new project_name
|
||||
end
|
||||
|
||||
def create_view project_name, view_name
|
||||
Project.validate_name project_name
|
||||
View.validate_name view_name
|
||||
raise "MissingProject" if not @projects.has_key? project_name
|
||||
|
||||
view = View.new view_name
|
||||
@projects[project_name].add_view view
|
||||
end
|
||||
|
||||
def to_yaml
|
||||
return {
|
||||
global: {},
|
||||
projects: @projects.values.map{ |p| p.to_hash }
|
||||
}.to_yaml
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initialize
|
||||
@projects = {}
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Test
|
||||
def self.test_project_create
|
||||
config = Kook::Config.instance
|
||||
config.create_project 'proj'
|
||||
end
|
||||
|
||||
def self.test_view_create
|
||||
config = Kook::Config.instance
|
||||
config.create_view 'proj', 'proj-root'
|
||||
config.create_view 'proj', 'proj-base'
|
||||
config.create_view 'proj', 'proj-3'
|
||||
|
||||
puts config.to_yaml
|
||||
end
|
||||
end
|
||||
|
||||
Test.test_project_create
|
||||
Test.test_view_create
|
7
lib/kook.rb
Normal file
7
lib/kook.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
require 'kook/exceptions'
|
||||
require 'kook/view'
|
||||
require 'kook/project'
|
||||
require 'kook/config'
|
||||
require 'kook/cli'
|
||||
|
242
lib/kook/cli.rb
Normal file
242
lib/kook/cli.rb
Normal file
|
@ -0,0 +1,242 @@
|
|||
require 'thor'
|
||||
|
||||
module Kook
|
||||
module CLI
|
||||
module KookHelper
|
||||
|
||||
def fail_for exception, params=nil
|
||||
STDERR.puts "ERROR(#{exception.class}) : #{exception}"
|
||||
STDERR.puts exception.backtrace
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
class OldConfig
|
||||
include Singleton
|
||||
include KookHelper
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
'global' => {}, # (ConfigKey_str => ConfigVal_str ) list
|
||||
'projects' => {}, # Project_str list
|
||||
'views' => {}, # (Project_str => View_str) list
|
||||
'commands' => {} # (Project_str => View_str) => Command list
|
||||
}
|
||||
|
||||
def initialize
|
||||
# load file
|
||||
@config = DEFAULT_CONFIG
|
||||
load_main
|
||||
@config
|
||||
end
|
||||
|
||||
|
||||
|
||||
def [] key
|
||||
@config[key]
|
||||
end
|
||||
end
|
||||
|
||||
class Project < Thor
|
||||
include KookHelper
|
||||
|
||||
desc "detect", "Detect current project"
|
||||
def detect
|
||||
project_name = current_project.nil? ? "-none-" : current_project
|
||||
say "Current project is #{project_name}."
|
||||
end
|
||||
|
||||
desc "list", "List projects"
|
||||
def list
|
||||
config.each_project do |project_name,project|
|
||||
pp project_name
|
||||
exist = File.exist? project.path
|
||||
display_path = (
|
||||
path.clone
|
||||
.gsub!(/#{ENV['HOME']}/,'~')
|
||||
.send(exist ? :green : :red)
|
||||
)
|
||||
puts "%- 24s %s" % [project_name, display_path]
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME: option for alternative path
|
||||
desc "add PROJECT [PATH]", "Register new project"
|
||||
def add project_name, project_path=nil
|
||||
|
||||
if project_path.nil? then
|
||||
project_path = Dir.pwd
|
||||
end
|
||||
project_path = File.expand_path project_path
|
||||
config.add_project project_name, project_path
|
||||
|
||||
say "Project #{project_name} registered on #{project_path}."
|
||||
rescue Exception => e
|
||||
fail_for e, project: project_name, path: project_path
|
||||
end
|
||||
|
||||
desc "rm PROJECT", "Unregister existing project"
|
||||
def rm project
|
||||
config['projects'].delete project
|
||||
config.save_main
|
||||
say "Project #{project} unregistered."
|
||||
end
|
||||
|
||||
desc "edit PROJECT", "Open editor on project file"
|
||||
def edit project
|
||||
if config['projects'].has_key? project then
|
||||
project_config_path = File.join CONFIG_DIR, "Kookfile"
|
||||
system "%s %s" % [ENV['EDITOR'], project_config_path]
|
||||
else
|
||||
raise "Project #{project} not found"
|
||||
end
|
||||
end
|
||||
# TODO: editcopy project to another name + base path
|
||||
# TODO: copy project to another name + base path
|
||||
#
|
||||
private
|
||||
|
||||
def config
|
||||
Config.instance
|
||||
end
|
||||
end
|
||||
|
||||
class View < Thor
|
||||
include KookHelper
|
||||
|
||||
desc "list [PROJECT]", "List view for a project"
|
||||
def list project=nil
|
||||
project ||= current_project
|
||||
validate_project_exists project
|
||||
|
||||
if config['views'].has_key? project then
|
||||
return if config['views'][project].nil?
|
||||
config['views'][project].each do |view,path|
|
||||
puts "%- 24s %s" % [view, path]
|
||||
|
||||
next if config['commands'][project].nil? or \
|
||||
config['commands'][project][view].nil?
|
||||
|
||||
config['commands'][project][view].each_index do |idx|
|
||||
puts " % 4d. %s" % [
|
||||
idx,
|
||||
config['commands'][project][view][idx]
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "add PROJECT VIEW", "Register new view"
|
||||
def add project, view, path=nil
|
||||
if path.nil? then
|
||||
path = Dir.pwd
|
||||
end
|
||||
project_rootdir = config['projects'][project]
|
||||
# simplify if current dir is a subdir of project base
|
||||
if path == project_rootdir then
|
||||
path = '.'
|
||||
else
|
||||
path.gsub!(/^#{project_rootdir}\//,'')
|
||||
end
|
||||
|
||||
if not config['views'].has_key? project then
|
||||
config['views'][project] = {}
|
||||
elsif config['views'][project].nil? then
|
||||
config['views'][project] = {}
|
||||
end
|
||||
#binding.pry
|
||||
config['views'][project][view] = path
|
||||
config.save_main
|
||||
end
|
||||
|
||||
desc "rm PROJECT VIEW", "Unregister existing view on project"
|
||||
def rm project, view
|
||||
# FIXME: validate project existance
|
||||
# FIXME: validate view existance
|
||||
config['views'][project].delete view
|
||||
config.save_main
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def config
|
||||
Config.instance
|
||||
end
|
||||
end
|
||||
|
||||
# FIXME: add helper validating project name
|
||||
# FIXME: add helper validating vie name for project
|
||||
class Command < Thor
|
||||
desc "add PROJECT VIEW COMMAND", "Add command for view "
|
||||
def add project, view, command
|
||||
unless config['commands'].has_key? project then
|
||||
config['commands'][project] = {}
|
||||
end
|
||||
if config['commands'][project].nil? then
|
||||
config['commands'][project] = {}
|
||||
end
|
||||
unless config['commands'][project].has_key? view then
|
||||
config['commands'][project][view] = []
|
||||
end
|
||||
config['commands'][project][view] << command
|
||||
config.save_main
|
||||
end
|
||||
|
||||
desc "rm PROJECT VIEW", "Remove command for view"
|
||||
def rm project, view, index
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def config
|
||||
Config.instance
|
||||
end
|
||||
end
|
||||
|
||||
class Main < Thor
|
||||
include KookHelper
|
||||
|
||||
desc "project SUBCOMMAND [options]", "Commands for managing projects"
|
||||
subcommand "project", CLI::Project
|
||||
|
||||
desc "view SUBCOMMAND [options]", "Commands for managing view"
|
||||
subcommand "view", CLI::View
|
||||
|
||||
desc "command SUBCOMMAND [options]", "Commands for managing commands"
|
||||
subcommand "command", CLI::Command
|
||||
|
||||
desc "fire PROJECT", "Run project environment"
|
||||
def fire project
|
||||
validate_project_name project
|
||||
validate_project_exists project
|
||||
pp config
|
||||
|
||||
raise "No view defined for #{project}" if not config['views'].has_key? project
|
||||
config['views'][project].each do |view,view_path|
|
||||
project_path = config['projects'][project]
|
||||
target = ENV['KONSOLE_DBUS_SERVICE'] || 'org.kde.konsole'
|
||||
session=`qdbus #{target} /Konsole newSession`.strip
|
||||
|
||||
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"cd #{project_path}\n\""
|
||||
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"cd #{view_path}\n\""
|
||||
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"clear\n\""
|
||||
system "qdbus org.kde.konsole /Sessions/#{session} setTitle 1 \"#{view}\""
|
||||
next unless config['commands'][project].has_key? view
|
||||
config['commands'][project][view].each do |command|
|
||||
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"#{command}\""
|
||||
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"\n\""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def config
|
||||
Config.instance
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
105
lib/kook/config.rb
Normal file
105
lib/kook/config.rb
Normal file
|
@ -0,0 +1,105 @@
|
|||
module Kook
|
||||
class Config
|
||||
include Singleton
|
||||
|
||||
CONFIG_DIR = File.join ENV['HOME'], '.config', 'kook'
|
||||
CONFIG_FILE = File.join CONFIG_DIR, 'config.yml'
|
||||
|
||||
class ExistingProject < RuntimeError ; end
|
||||
class MissingProject < RuntimeError ; end
|
||||
|
||||
def add_project project_name, project_path=nil
|
||||
raise ExistingProject if @projects.has_key? project_name
|
||||
|
||||
project_data = Project.new project_name
|
||||
project_data.path = project_path
|
||||
@projects[project_name] = project_data
|
||||
save
|
||||
end
|
||||
|
||||
def each_project
|
||||
@projects.each do |p,data|
|
||||
yield p,data
|
||||
end
|
||||
end
|
||||
|
||||
def add_view project_name, view_name
|
||||
Project.validate_name project_name
|
||||
View.validate_name view_name
|
||||
raise MissingProject if not @projects.has_key? project_name
|
||||
|
||||
view = View.new view_name
|
||||
@projects[project_name].add_view view
|
||||
save
|
||||
end
|
||||
|
||||
def load
|
||||
yaml = YAML::load_file CONFIG_FILE
|
||||
|
||||
yaml['projects'].each do |project_name,project_path|
|
||||
pp project_path
|
||||
#project_path = @config['projects'][project]
|
||||
project_file = kook_file_for project_path
|
||||
|
||||
if File.exist? project_file then
|
||||
subconfig = YAML::load_file project_file
|
||||
next if not subconfig
|
||||
@config['views'][project] = subconfig['views']
|
||||
@config['commands'][project] = subconfig['commands']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def save
|
||||
if not File.exist? CONFIG_DIR then
|
||||
FileUtils.mkdir_p CONFIG_DIR
|
||||
end
|
||||
|
||||
@projects.each do |project_name,project_data|
|
||||
# FIXME: test if project configuration is dirty
|
||||
#pp project_data
|
||||
project_file = File.join project_data.path, "Kookfile"
|
||||
|
||||
File.open(project_file, "w") do |file|
|
||||
file.write project_data.to_hash.to_yaml
|
||||
end
|
||||
end
|
||||
|
||||
File.open(CONFIG_FILE, "w") do |file|
|
||||
file.write to_yaml
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def current_project
|
||||
current_dir = Dir.pwd
|
||||
@projects.each do |project_name,project|
|
||||
if current_dir =~ /^#{project.path}/ then
|
||||
return project_name
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def kook_file_for project_path
|
||||
kook_files = Dir.glob(File.join(project_path, 'Kookfile'))
|
||||
raise MissingProjectFile if kook_files.empty?
|
||||
kook_files.first
|
||||
end
|
||||
|
||||
def to_yaml
|
||||
return {
|
||||
'global' => {},
|
||||
'projects' => @projects.values.map{ |p| { p.name => p.path } }
|
||||
}.to_yaml
|
||||
end
|
||||
|
||||
def initialize
|
||||
super
|
||||
@projects = {}
|
||||
self.load
|
||||
end
|
||||
end
|
||||
end
|
4
lib/kook/exceptions.rb
Normal file
4
lib/kook/exceptions.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
module Kook
|
||||
class MissingProjectConfiguration < RuntimeError ; end
|
||||
end
|
71
lib/kook/project.rb
Normal file
71
lib/kook/project.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
require 'kook/exceptions'
|
||||
|
||||
module Kook
|
||||
class Project
|
||||
attr_reader :name, :path
|
||||
attr_accessor :description
|
||||
|
||||
class MissingProjectFile < RuntimeError ; end
|
||||
class InvalidProjectName < RuntimeError ; end
|
||||
PROJECT_NAME_MIN_SIZE = 4
|
||||
PROJECT_NAME_MAX_SIZE = 12
|
||||
|
||||
def initialize project_name
|
||||
self.class.validate_name project_name
|
||||
@name = project_name
|
||||
@description = nil
|
||||
@path = nil
|
||||
@views = {}
|
||||
end
|
||||
|
||||
def path= path
|
||||
# FIXME: validate current path exists
|
||||
#
|
||||
if not (File.exist? path and File.directory? path) then
|
||||
raise "PathDoesNotExist #{path}"
|
||||
end
|
||||
@path = path
|
||||
end
|
||||
|
||||
def add_view view
|
||||
raise "ExistingView #{view.name}" if @views.has_key? view.name
|
||||
@views[view.name] = view
|
||||
end
|
||||
|
||||
def remove_view view_name
|
||||
View.validate_name view_name
|
||||
return @view.delete(view_name)
|
||||
end
|
||||
|
||||
def to_hash
|
||||
return {
|
||||
project: @name,
|
||||
description: @description,
|
||||
path: @path,
|
||||
views: @views.values.map{ |v| v.to_hash }
|
||||
}
|
||||
end
|
||||
|
||||
def from_hash project_hash
|
||||
@name = project_hash[:project]
|
||||
@description = project_hash[:description]
|
||||
@path = project_hash[:path]
|
||||
project_hash[:views].each do |hash_view|
|
||||
view = View.new do |v|
|
||||
v.from_hash hash_view
|
||||
end
|
||||
add_view view
|
||||
end
|
||||
end
|
||||
|
||||
def self.validate_name name
|
||||
raise "TooShortProjectIdentifier" if name.size < Project::PROJECT_NAME_MIN_SIZE
|
||||
raise "TooLongProjectIdentifier" if name.size > Project::PROJECT_NAME_MAX_SIZE
|
||||
if not name =~ /^\w+$/ then
|
||||
raise "BadProjectIdentifier #{name}"
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
39
lib/kook/view.rb
Normal file
39
lib/kook/view.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
module Kook
|
||||
class View
|
||||
attr_reader :name, :path
|
||||
attr_accessor :description
|
||||
VIEW_NAME_MIN_SIZE = 4
|
||||
VIEW_NAME_MAX_SIZE = 12
|
||||
|
||||
def initialize name
|
||||
self.class.validate_name name
|
||||
@name = name
|
||||
@path = nil
|
||||
@commands = {}
|
||||
end
|
||||
|
||||
def self.validate_name name
|
||||
raise "TooShortViewIdentifier" if name.size < View::VIEW_NAME_MIN_SIZE
|
||||
raise "TooLongViewIdentifier" if name.size > View::VIEW_NAME_MAX_SIZE
|
||||
if not name =~ /^[\w-]+$/ then
|
||||
raise "BadViewIdentifier #{name}"
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def to_hash
|
||||
return {
|
||||
view: @name,
|
||||
path: @path,
|
||||
commands: @commands.values
|
||||
}
|
||||
end
|
||||
|
||||
def from_hash view_hash
|
||||
@name = view_hash[:view]
|
||||
@path = view_hash[:path]
|
||||
@commands = view_hash[:commands]
|
||||
end
|
||||
end
|
||||
end
|
18
test.sh
Executable file
18
test.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/bin/sh
|
||||
|
||||
PATH=./bin:$PATH
|
||||
|
||||
set -e
|
||||
|
||||
fail() {
|
||||
set +x
|
||||
echo "ERROR: $*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set -x
|
||||
|
||||
kook project add kook1 . || fail "test1"
|
||||
kook project add kook2 || fail "test2"
|
||||
kook project list || fail "test3"
|
||||
|
Loading…
Reference in a new issue