Compare commits
48 commits
Author | SHA1 | Date | |
---|---|---|---|
|
a707be5c63 | ||
|
06c00e545c | ||
|
798932046a | ||
|
8216c91e88 | ||
|
a5dbbb1d49 | ||
|
d338b1c924 | ||
|
30f8d5e9a0 | ||
|
ddbb2903cb | ||
|
b1c0c2b5ef | ||
|
b750e281ef | ||
|
d46d6a0fd4 | ||
|
03481e6ee4 | ||
fbee330868 | |||
53d34ddbf1 | |||
1e72d86d54 | |||
f8ce378b99 | |||
d9edb054ad | |||
6886f36c08 | |||
55d203da8d | |||
|
470d0b42f8 | ||
|
9f045fb5d9 | ||
|
2d6d5b21e3 | ||
|
58ad2950f8 | ||
|
19e6e14f01 | ||
|
3b0e5a2ce3 | ||
|
0a23465b98 | ||
|
93be352501 | ||
|
841cde2dc2 | ||
f5896f6b2d | |||
d3ec76f37a | |||
90576fb2b4 | |||
4cb5238065 | |||
52731febd5 | |||
def5c85f68 | |||
|
c0f0c890ca | ||
cda1edf92c | |||
ffa3c6c39e | |||
|
f200005e92 | ||
|
cdcec384f0 | ||
|
34b3f80b3e | ||
|
93a9772ee3 | ||
|
a4d9c5b39b | ||
|
f90bbee818 | ||
|
4c4f0e1ddc | ||
|
ef6c37e43e | ||
d6d5e66cfa | |||
|
488d4616e0 | ||
|
a61d466bd1 |
24 changed files with 942 additions and 82 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
*.a
|
||||||
|
/.bundle/
|
||||||
|
/coverage/
|
||||||
|
/doc/
|
||||||
|
/Gemfile.lock
|
||||||
|
/Kookfile
|
||||||
|
mkmf.log
|
||||||
|
*.o
|
||||||
|
/pkg/
|
||||||
|
*.so
|
||||||
|
/spec/reports/
|
||||||
|
/tmp/
|
||||||
|
/vendor/
|
||||||
|
/_yardoc/
|
||||||
|
/.yardoc
|
4
Gemfile
Normal file
4
Gemfile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# A sample Gemfile
|
||||||
|
source "https://rubygems.org"
|
||||||
|
|
||||||
|
gemspec
|
22
LICENSE.md
Normal file
22
LICENSE.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright (c) 2015 Glenn Y. Rolland
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
78
README.md
78
README.md
|
@ -1,10 +1,74 @@
|
||||||
KoProj is a tool for managing console project environments
|
# Kook
|
||||||
|
|
||||||
Ex: Project X require 3 terminals, with name A, B, C :
|
Kook is a helper for opening your projects environments in tabs of KDE Konsole.
|
||||||
|
|
||||||
A : must be in directory ~/
|
|
||||||
B : must be in directory ~/foo
|
|
||||||
run command X
|
|
||||||
C : must be in directory ~/bar
|
|
||||||
run command Y
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Simply install kook via the 'gem' package manager
|
||||||
|
|
||||||
|
$ gem install kook
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Imagine, that for working on your project, you requires multiple terminal consoles,
|
||||||
|
with different tools in them.
|
||||||
|
|
||||||
|
Let say that :
|
||||||
|
|
||||||
|
A : must be in directory ~/src/myProject/
|
||||||
|
B : must be in directory ~/src/myProject/app
|
||||||
|
and run command "$EDITOR ."
|
||||||
|
C : must be in directory ~/src/myProject/log
|
||||||
|
and run command "tail -f development.log"
|
||||||
|
|
||||||
|
Kook aims to prepare your project environment, just like you want it to be,
|
||||||
|
with all you tabs and the commands inside in the right directories. Everything
|
||||||
|
in one single command.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork it ( http://github.com/glenux/kook/fork )
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
|
4. Push to the branch (`git push origin my-new-feature`)
|
||||||
|
5. Create new Pull Request
|
||||||
|
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
* Tmuxinator (the same goal, based on tmux instead of Konsole)
|
||||||
|
|
||||||
|
# Kook
|
||||||
|
|
||||||
|
TODO: Write a gem description
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Add this line to your application's Gemfile:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
gem 'kook'
|
||||||
|
```
|
||||||
|
|
||||||
|
And then execute:
|
||||||
|
|
||||||
|
$ bundle
|
||||||
|
|
||||||
|
Or install it yourself as:
|
||||||
|
|
||||||
|
$ gem install kook
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
TODO: Write usage instructions here
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Fork it ( https://github.com/[my-github-username]/kook/fork )
|
||||||
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||||
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
||||||
|
4. Push to the branch (`git push origin my-new-feature`)
|
||||||
|
5. Create a new Pull Request
|
||||||
|
|
7
Rakefile
Normal file
7
Rakefile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
require 'rspec/core/rake_task'
|
||||||
|
require "bundler/gem_tasks"
|
||||||
|
|
||||||
|
RSpec::Core::RakeTask.new(:spec)
|
||||||
|
|
||||||
|
task :default => :spec
|
16
TODO.md
Normal file
16
TODO.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
Kook Task List
|
||||||
|
==============
|
||||||
|
|
||||||
|
Package as a gem
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- ( ) Write gemspec
|
||||||
|
- ( ) Migrate gems & check versions
|
||||||
|
|
||||||
|
|
||||||
|
Marketing
|
||||||
|
---------
|
||||||
|
|
||||||
|
- ( ) Rename project
|
||||||
|
- ( ) Write documentation
|
||||||
|
|
23
bin/kook
Executable file
23
bin/kook
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
# vim: set syntax=ruby:
|
||||||
|
|
||||||
|
require 'yaml'
|
||||||
|
require 'singleton'
|
||||||
|
require 'pathname'
|
||||||
|
|
||||||
|
require 'colorize'
|
||||||
|
|
||||||
|
DATA_DIR = (Pathname.new(__FILE__).dirname + '..').realpath.to_s
|
||||||
|
|
||||||
|
require 'thor'
|
||||||
|
require 'kook'
|
||||||
|
|
||||||
|
begin
|
||||||
|
Kook::CLI::Main.start(ARGV)
|
||||||
|
rescue Exception => exception
|
||||||
|
# In case of unhandled exception.
|
||||||
|
# FIXME: Manage display & create log file
|
||||||
|
STDERR.puts "ERROR(#{exception.class}) : #{exception}"
|
||||||
|
STDERR.puts exception.backtrace
|
||||||
|
exit 1
|
||||||
|
end
|
51
bin/kotam
51
bin/kotam
|
@ -1,51 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
|
|
||||||
KOTAM_DATA_DIR=$(cd `dirname "$0"`; cd ../lib ; pwd )
|
|
||||||
KOTAM_CONFIG_DIR=$HOME/.config/kotam
|
|
||||||
|
|
||||||
. $KOTAM_DATA_DIR/base.sh
|
|
||||||
|
|
||||||
## Expected usage :
|
|
||||||
#
|
|
||||||
# kotam exec <name>
|
|
||||||
# kotam init <name>
|
|
||||||
#
|
|
||||||
|
|
||||||
mkdir -p $KOTAM_CONFIG_DIR
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
arg=${1:-}
|
|
||||||
opt=${2:-}
|
|
||||||
case $arg in
|
|
||||||
-l|--list) #list projects
|
|
||||||
echo "List of projects :"
|
|
||||||
ls $KOTAM_CONFIG_DIR/*.kotam 2> /dev/null
|
|
||||||
;;
|
|
||||||
-e) # edit project
|
|
||||||
shift
|
|
||||||
project="$opt"
|
|
||||||
if [ -z "$project" ]; then
|
|
||||||
echo "ERROR: project name missing" >&2
|
|
||||||
exit 1
|
|
||||||
elif [ ! -e "$KOTAM_CONFIG_DIR/$project.kotam" ]; then
|
|
||||||
echo "ERROR: unknown project $project" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
"$EDITOR" "$KOTAM_CONFIG_DIR/$project.kotam"
|
|
||||||
;;
|
|
||||||
-c) # create
|
|
||||||
;;
|
|
||||||
-d) # destroy
|
|
||||||
;;
|
|
||||||
*) #enter into project
|
|
||||||
project="$arg"
|
|
||||||
if [ ! -e "$KOTAM_CONFIG_DIR/$project.kotam" ]; then
|
|
||||||
echo "ERROR: unknown project $project" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
. "$KOTAM_CONFIG_DIR/$project.kotam"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
33
kook.gemspec
Normal file
33
kook.gemspec
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# coding: utf-8
|
||||||
|
lib = File.expand_path('../lib', __FILE__)
|
||||||
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||||
|
require 'kook/version'
|
||||||
|
|
||||||
|
Gem::Specification.new do |spec|
|
||||||
|
spec.name = "kook"
|
||||||
|
spec.version = Kook::VERSION
|
||||||
|
spec.authors = ["Glenn Y. Rolland"]
|
||||||
|
spec.email = ["glenux@glenux.net"]
|
||||||
|
spec.summary = %q{Kook is a helper for opening your projects environments in tabs of KDE Konsole}
|
||||||
|
#spec.description = %q{TODO: Write a longer description. Optional.}
|
||||||
|
spec.homepage = "http://github.com/glenux/kook"
|
||||||
|
spec.license = "MIT"
|
||||||
|
|
||||||
|
spec.rubyforge_project = "kook"
|
||||||
|
|
||||||
|
spec.files = `git ls-files`.split($/)
|
||||||
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
||||||
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
||||||
|
spec.require_paths = ["lib"]
|
||||||
|
spec.bindir = 'bin'
|
||||||
|
spec.post_install_message = "Thanks for installing!"
|
||||||
|
|
||||||
|
spec.add_development_dependency "bundler", "~> 1.5"
|
||||||
|
spec.add_development_dependency "rake"
|
||||||
|
spec.add_development_dependency "rspec"
|
||||||
|
# spec.add_development_dependency "pry"
|
||||||
|
# spec.add_development_dependency "rm-readline"
|
||||||
|
|
||||||
|
spec.add_runtime_dependency "thor"
|
||||||
|
spec.add_runtime_dependency "colorize"
|
||||||
|
end
|
24
lib/base.sh
24
lib/base.sh
|
@ -1,24 +0,0 @@
|
||||||
|
|
||||||
kotam_run() {
|
|
||||||
local cmd="$*"
|
|
||||||
qdbus org.kde.konsole /Sessions/${session} sendText "$cmd"
|
|
||||||
qdbus org.kde.konsole /Sessions/${session} sendText "
|
|
||||||
"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
kotam_newtab() {
|
|
||||||
#dbus-send --session --dest=${KONSOLE_DBUS_SERVICE} --type=method_call \
|
|
||||||
# --print-reply /konsole/MainWindow_1 org.kde.KMainWindow.activateAction string:"new-tab"
|
|
||||||
|
|
||||||
session=$(qdbus org.kde.konsole /Konsole newSession)
|
|
||||||
}
|
|
||||||
|
|
||||||
kotam_renametab() {
|
|
||||||
#sessionno=$1
|
|
||||||
tabname=$1
|
|
||||||
#session="/Sessions/${sessionno}"
|
|
||||||
#dbus-send --session --dest=${KONSOLE_DBUS_SERVICE} --type=method_call --print-reply ${session} org.kde.konsole.Session.setTitle int32:1 string:"$tabname"
|
|
||||||
qdbus org.kde.konsole /Sessions/${session} setTitle 1 "$tabname"
|
|
||||||
}
|
|
||||||
|
|
8
lib/kook.rb
Normal file
8
lib/kook.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
require 'kook/version'
|
||||||
|
require 'kook/exceptions'
|
||||||
|
require 'kook/view'
|
||||||
|
require 'kook/project'
|
||||||
|
require 'kook/app'
|
||||||
|
require 'kook/cli'
|
||||||
|
|
203
lib/kook/app.rb
Normal file
203
lib/kook/app.rb
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
module Kook
|
||||||
|
class App
|
||||||
|
CONFIG_DIR = File.join ENV['HOME'], '.config', 'kook'
|
||||||
|
CONFIG_FILE = File.join CONFIG_DIR, 'config.yml'
|
||||||
|
|
||||||
|
attr_accessor :verbose
|
||||||
|
|
||||||
|
class ExistingProject < RuntimeError ; end
|
||||||
|
class MissingProject < RuntimeError ; end
|
||||||
|
class MissingProjectFile < RuntimeError ; end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
@projects = {}
|
||||||
|
@config_file = CONFIG_FILE
|
||||||
|
@verbose = false
|
||||||
|
@current_project = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_projects
|
||||||
|
projects_exist = false
|
||||||
|
|
||||||
|
# get boundary for project name + margin
|
||||||
|
column_width = @projects.map{ |name,data| name }.max
|
||||||
|
|
||||||
|
@projects.each do |project_name,project_data|
|
||||||
|
projects_exist = true
|
||||||
|
exist = File.exist? project_data.path
|
||||||
|
display_path = (
|
||||||
|
project_data.path.clone
|
||||||
|
.gsub!(/#{ENV['HOME']}/,'~')
|
||||||
|
.send(exist ? :green : :red)
|
||||||
|
)
|
||||||
|
puts "%- #{column_width}s %s" % [project_name, display_path]
|
||||||
|
end
|
||||||
|
STDERR.puts "No project found." if not projects_exist
|
||||||
|
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 edit_project project_name
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
|
||||||
|
project_config_path = File.join @projects[project_name].path, "Kookfile"
|
||||||
|
system "%s %s" % [ENV['EDITOR'], project_config_path]
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_project project_name
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
@projects.delete project_name
|
||||||
|
save
|
||||||
|
end
|
||||||
|
|
||||||
|
def fire_project project_name
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
|
||||||
|
project_path = @projects[project_name].path
|
||||||
|
@projects[project_name].fire
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_view project_name, view_name, view_path=nil
|
||||||
|
View.validate_name view_name
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
|
||||||
|
project_path = @projects[project_name].path
|
||||||
|
|
||||||
|
# simplify if current dir is a subdir of project base
|
||||||
|
if view_path == project_path then
|
||||||
|
view_path = '.'
|
||||||
|
else
|
||||||
|
view_path = (view_path
|
||||||
|
.gsub(/^#{project_path}\//,'')
|
||||||
|
.gsub(/\/$/,'')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@projects[project_name].create_view view_name, view_path
|
||||||
|
save
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_command project_name, view_name, command
|
||||||
|
View.validate_name view_name
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
|
||||||
|
@projects[project_name].add_command view_name, command
|
||||||
|
save
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_command project_name, view_name, command_idx
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
|
||||||
|
@projects[project_name].remove_command view_name, command_idx
|
||||||
|
save
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_views project_name
|
||||||
|
raise MissingProject if not @projects.has_key? project_name
|
||||||
|
|
||||||
|
@projects[project_name].each_view do |view_name,view_data|
|
||||||
|
puts "%- 24s %s" % [view_name, view_data.path]
|
||||||
|
|
||||||
|
if view_data.commands.empty?
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
view_data.commands.each_index do |idx|
|
||||||
|
puts "* % 4d. %s" % [idx, view_data.commands[idx]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load config_file=nil
|
||||||
|
config_file ||= @config_file
|
||||||
|
@config_file = config_file
|
||||||
|
|
||||||
|
if not File.exist? config_file then
|
||||||
|
STDERR.puts "Missing config file #{config_file}" if @verbose
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
STDERR.puts "Loading main configuration #{config_file}..." if @verbose
|
||||||
|
yaml = YAML::load_file config_file
|
||||||
|
|
||||||
|
yaml['projects'].each do |project_name,project_path|
|
||||||
|
# pp project_path
|
||||||
|
#project_path = @config['projects'][project]
|
||||||
|
project_file = File.join project_path, "Kookfile"
|
||||||
|
|
||||||
|
STDERR.puts "Loading sub configuration #{project_file}..." if @verbose
|
||||||
|
if File.exist? project_file then
|
||||||
|
subconfig = YAML::load_file project_file
|
||||||
|
next if not subconfig
|
||||||
|
|
||||||
|
@projects[project_name] = Project.from_hash subconfig, project_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def save config_file=nil
|
||||||
|
config_file ||= @config_file
|
||||||
|
config_dir = File.dirname config_file
|
||||||
|
if not File.exist? config_dir then
|
||||||
|
FileUtils.mkdir_p config_dir
|
||||||
|
end
|
||||||
|
|
||||||
|
STDERR.puts "Saving to #{config_file}" if @verbose
|
||||||
|
|
||||||
|
@projects.each do |project_name,project_data|
|
||||||
|
# FIXME: test if project configuration is dirty
|
||||||
|
project_file = File.join project_data.path, "Kookfile"
|
||||||
|
|
||||||
|
File.open(project_file, "w") do |file|
|
||||||
|
file.puts "# This file was generated by Kook #{VERSION}"
|
||||||
|
file.puts "# You can get it at https://github.com/glenux/kook"
|
||||||
|
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= project_name
|
||||||
|
# FIXME: validate project name
|
||||||
|
@current_project = project_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_project
|
||||||
|
return @current_project if not @current_project.nil?
|
||||||
|
|
||||||
|
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 to_yaml
|
||||||
|
return {
|
||||||
|
'global' => {},
|
||||||
|
'projects' => Hash[@projects.map{ |p,v| [v.name, v.path] }]
|
||||||
|
}.to_yaml
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
174
lib/kook/cli.rb
Normal file
174
lib/kook/cli.rb
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
require 'thor'
|
||||||
|
|
||||||
|
module Kook
|
||||||
|
module CLI
|
||||||
|
module KookHelper
|
||||||
|
def before_filter options
|
||||||
|
@app = App.new
|
||||||
|
@app.load options[:config]
|
||||||
|
@app.verbose = options[:verbose]
|
||||||
|
@app.current_project = options[:project]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Inject our extensions in thor instances
|
||||||
|
def self.included(base)
|
||||||
|
base.class_eval do
|
||||||
|
#if ancestors.include? Thor::Group
|
||||||
|
# namespace self.name.split('::').last.downcase.to_sym
|
||||||
|
#end
|
||||||
|
|
||||||
|
class_option :verbose,
|
||||||
|
type: :boolean,
|
||||||
|
default: false,
|
||||||
|
aliases: '-v',
|
||||||
|
desc: 'Whether to output informative debug'
|
||||||
|
|
||||||
|
class_option :config,
|
||||||
|
type: :string,
|
||||||
|
default: nil,
|
||||||
|
aliases: '-c',
|
||||||
|
desc: 'Configuration file'
|
||||||
|
|
||||||
|
class_option :project,
|
||||||
|
type: :string,
|
||||||
|
default: nil,
|
||||||
|
aliases: '-p',
|
||||||
|
desc: 'Target project'
|
||||||
|
|
||||||
|
class_option :directory,
|
||||||
|
type: :string,
|
||||||
|
default: nil,
|
||||||
|
aliases: '-d',
|
||||||
|
desc: 'Target directory'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Project < Thor
|
||||||
|
include KookHelper
|
||||||
|
|
||||||
|
desc "detect", "Detect current project"
|
||||||
|
def detect
|
||||||
|
before_filter options
|
||||||
|
current_project = @app.current_project
|
||||||
|
project_name = current_project.nil? ? "-none-" : current_project
|
||||||
|
say "Current project is #{project_name}."
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "list", "List projects"
|
||||||
|
def list
|
||||||
|
before_filter options
|
||||||
|
@app.list_projects
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "add PROJECT [-d DIRECTORY]", "Register new project"
|
||||||
|
def add project_name
|
||||||
|
before_filter options
|
||||||
|
project_path = options[:directory]
|
||||||
|
|
||||||
|
if project_path.nil? then
|
||||||
|
project_path = Dir.pwd
|
||||||
|
end
|
||||||
|
project_path = File.expand_path project_path
|
||||||
|
@app.add_project project_name, project_path
|
||||||
|
|
||||||
|
say "Project #{project_name} registered on #{project_path}."
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "rm PROJECT", "Unregister existing project"
|
||||||
|
def rm project
|
||||||
|
before_filter options
|
||||||
|
@app.remove_project project
|
||||||
|
say "Project #{project} unregistered."
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "edit [-p PROJECT]", "Open editor on project file"
|
||||||
|
def edit
|
||||||
|
before_filter options
|
||||||
|
project_name ||= @app.current_project
|
||||||
|
|
||||||
|
@app.edit_project project_name
|
||||||
|
end
|
||||||
|
# TODO: editcopy project to another name + base path
|
||||||
|
# TODO: copy project to another name + base path
|
||||||
|
end
|
||||||
|
|
||||||
|
class View < Thor
|
||||||
|
include KookHelper
|
||||||
|
|
||||||
|
desc "list [-p PROJECT]", "List view for a project"
|
||||||
|
def list
|
||||||
|
before_filter options
|
||||||
|
project_name = @app.current_project
|
||||||
|
|
||||||
|
@app.list_views project_name
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "add VIEW [-p PROJECT] [-d DIRECTORY]", "Register new view"
|
||||||
|
def add view_name
|
||||||
|
before_filter options
|
||||||
|
project_name = @app.current_project
|
||||||
|
|
||||||
|
view_path = options[:directory]
|
||||||
|
if view_path.nil? then
|
||||||
|
view_path = Dir.pwd
|
||||||
|
end
|
||||||
|
|
||||||
|
@app.add_view project_name, view_name, view_path
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "rm VIEW [-p PROJECT]", "Unregister existing view on project"
|
||||||
|
def rm view_name
|
||||||
|
before_filter options
|
||||||
|
project_name = @app.current_project
|
||||||
|
|
||||||
|
@app.remove_view project_name, view_name, view_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# FIXME: add helper validating project name
|
||||||
|
# FIXME: add helper validating vie name for project
|
||||||
|
class Command < Thor
|
||||||
|
include KookHelper
|
||||||
|
|
||||||
|
desc "add VIEW COMMAND [-p PROJECT]", "Add command for view"
|
||||||
|
def add view_name, command
|
||||||
|
before_filter options
|
||||||
|
project_name = @app.current_project
|
||||||
|
|
||||||
|
@app.add_command project_name, view_name, command
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "rm VIEW INDEX [-p PROJECT]", "Remove command for view"
|
||||||
|
def rm view_name, command_index
|
||||||
|
before_filter options
|
||||||
|
project_name = @app.current_project
|
||||||
|
|
||||||
|
@app.remove_command project_name, view_name, command_index.to_i
|
||||||
|
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 "start [-p PROJECT]", "Run project environment"
|
||||||
|
def start
|
||||||
|
before_filter options
|
||||||
|
project_name = @app.current_project
|
||||||
|
|
||||||
|
@app.fire_project project_name
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
0
lib/kook/plugins/generic.rb
Normal file
0
lib/kook/plugins/generic.rb
Normal file
0
lib/kook/plugins/konsole.rb
Normal file
0
lib/kook/plugins/konsole.rb
Normal file
0
lib/kook/plugins/screen.rb
Normal file
0
lib/kook/plugins/screen.rb
Normal file
0
lib/kook/plugins/tmux.rb
Normal file
0
lib/kook/plugins/tmux.rb
Normal file
119
lib/kook/project.rb
Normal file
119
lib/kook/project.rb
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
|
||||||
|
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 = 15
|
||||||
|
|
||||||
|
def initialize project_name
|
||||||
|
self.class.validate_name project_name
|
||||||
|
@name = project_name
|
||||||
|
@description = nil
|
||||||
|
@path = nil
|
||||||
|
@views = {}
|
||||||
|
|
||||||
|
yield self if block_given?
|
||||||
|
self
|
||||||
|
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 fire
|
||||||
|
target = ENV['KONSOLE_DBUS_SERVICE'] || 'org.kde.konsole'
|
||||||
|
window = ENV['KONSOLE_DBUS_WINDOW'] || '/Konsole'
|
||||||
|
|
||||||
|
# FIXME: use runCommand instead of sendText ?
|
||||||
|
|
||||||
|
@views.each do |view,view_data|
|
||||||
|
session=`qdbus #{target} #{window} newSession`.strip
|
||||||
|
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"cd #{@path}\n\""
|
||||||
|
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"cd #{view_data.path}\n\""
|
||||||
|
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"clear\n\""
|
||||||
|
system "qdbus org.kde.konsole /Sessions/#{session} setTitle 1 \"#{view}\""
|
||||||
|
|
||||||
|
view_data.commands.each do |command|
|
||||||
|
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"#{command}\""
|
||||||
|
system "qdbus org.kde.konsole /Sessions/#{session} sendText \"\n\""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_view view_name, view_path
|
||||||
|
raise ExistingView, view_name if @views.has_key? view_name
|
||||||
|
View.validate_name view_name
|
||||||
|
|
||||||
|
@views[view_name] = View.new view_name, view_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_view view_data
|
||||||
|
raise ExistingView, view_data.name if @views.has_key? view_data.name
|
||||||
|
|
||||||
|
@views[view_data.name] = view_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_view view_name
|
||||||
|
raise MissingView, view_name if not @views.has_key? view_name
|
||||||
|
return @view.delete(view_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_command view_name, command
|
||||||
|
raise MissingView, view_name if not @views.has_key? view_name
|
||||||
|
@views[view_name].commands << command
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_command view_name, command_idx
|
||||||
|
raise MissingView, view_name if not @views.has_key? view_name
|
||||||
|
@views[view_name].commands.delete_at(command_idx)
|
||||||
|
end
|
||||||
|
|
||||||
|
def each_view
|
||||||
|
#pp @views
|
||||||
|
@views.each do |view_name, view_data|
|
||||||
|
yield view_name, view_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_hash
|
||||||
|
return {
|
||||||
|
'project' => @name,
|
||||||
|
'description' => @description,
|
||||||
|
#'path' => @path,
|
||||||
|
'views' => @views.values.map{ |v| v.to_hash }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_hash project_hash, project_path
|
||||||
|
project = Project.new project_hash['project'] do |p|
|
||||||
|
p.description = project_hash['description']
|
||||||
|
p.path = project_path
|
||||||
|
|
||||||
|
project_hash['views'].each do |view_hash|
|
||||||
|
view_data = View.from_hash view_hash
|
||||||
|
p.add_view view_data
|
||||||
|
end
|
||||||
|
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(\S+)$/ then
|
||||||
|
raise "BadProjectIdentifier #{name}"
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
3
lib/kook/version.rb
Normal file
3
lib/kook/version.rb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module Kook
|
||||||
|
VERSION = "0.1.0.dev"
|
||||||
|
end
|
49
lib/kook/view.rb
Normal file
49
lib/kook/view.rb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
module Kook
|
||||||
|
class View
|
||||||
|
attr_reader :name, :path, :commands
|
||||||
|
attr_accessor :description
|
||||||
|
VIEW_NAME_MIN_SIZE = 3
|
||||||
|
VIEW_NAME_MAX_SIZE = 12
|
||||||
|
|
||||||
|
def initialize name, path=nil
|
||||||
|
self.class.validate_name name
|
||||||
|
@name = name
|
||||||
|
@path = path
|
||||||
|
@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
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_command command
|
||||||
|
@commands << command
|
||||||
|
end
|
||||||
|
|
||||||
|
def rm_command command_index
|
||||||
|
@command.delete command_index
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_hash view_hash
|
||||||
|
view = View.new view_hash['view'], view_hash['path']
|
||||||
|
view_hash['commands'].each do |c|
|
||||||
|
view.add_command c
|
||||||
|
end
|
||||||
|
return view
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
61
spec/spec_helper.rb
Normal file
61
spec/spec_helper.rb
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Load all spec files
|
||||||
|
Dir["./spec/support/**/*.rb"].each {|f| require f}
|
||||||
|
|
||||||
|
RSpec.configure do |config|
|
||||||
|
# Allows using build(), create(), etc. without the "FactoryGirl." part.
|
||||||
|
config.include FactoryGirl::Syntax::Methods
|
||||||
|
|
||||||
|
config.before(:each) do
|
||||||
|
$0 = "kook" # Pretend we're running as 'kook'
|
||||||
|
ARGV.clear # Make sure no args are passed to the commands.
|
||||||
|
@directory = Dir.mktmpdir('kook-spec-') # Create a temp directory to work in.
|
||||||
|
@orig_directory = Dir.pwd # Save the original directory.
|
||||||
|
Dir.chdir(@directory) # Change to it. pwd() is the temp directory in the examples.
|
||||||
|
end
|
||||||
|
|
||||||
|
config.after(:each) do
|
||||||
|
Dir.chdir(@orig_directory) # Change back to the origin directory.
|
||||||
|
FileUtils.rmtree(@directory) # Remove the temp directory.
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Captures the output for analysis later
|
||||||
|
#
|
||||||
|
# @example Capture `$stderr`
|
||||||
|
#
|
||||||
|
# output = capture(:stderr) { $stderr.puts "this is captured" }
|
||||||
|
#
|
||||||
|
# @param [Symbol] stream `:stdout` or `:stderr`
|
||||||
|
# @yield The block to capture stdout/stderr for.
|
||||||
|
# @return [String] The contents of $stdout or $stderr
|
||||||
|
def capture(stream)
|
||||||
|
begin
|
||||||
|
stream = stream.to_s
|
||||||
|
eval "$#{stream} = StringIO.new"
|
||||||
|
yield
|
||||||
|
result = eval("$#{stream}").string
|
||||||
|
ensure
|
||||||
|
eval("$#{stream} = #{stream.upcase}")
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
# Silences the output stream
|
||||||
|
#
|
||||||
|
# @example Silence `$stdout`
|
||||||
|
#
|
||||||
|
# silence(:stdout) { $stdout.puts "hi" }
|
||||||
|
#
|
||||||
|
# @param [IO] stream The stream to use such as $stderr or $stdout
|
||||||
|
# @return [nil]
|
||||||
|
alias :silence :capture
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
EXAMPLES_DIR = Pathname.new(__FILE__).dirname + 'examples'
|
||||||
|
|
60
spec/test_project.rb
Executable file
60
spec/test_project.rb
Executable file
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
require 'singleton'
|
||||||
|
require 'yaml'
|
||||||
|
require 'pp'
|
||||||
|
|
||||||
|
module Kook
|
||||||
|
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
|
70
test.sh
Executable file
70
test.sh
Executable file
|
@ -0,0 +1,70 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PATH=./bin:$PATH
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
KOOK_TEST_CONFIG="$(pwd)/test.config.yml"
|
||||||
|
KOOK_OPTS="--verbose --config $KOOK_TEST_CONFIG"
|
||||||
|
TEST_TITLE=""
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "ERROR: $TEST_TITLE"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
test_cleanup() {
|
||||||
|
rm -f $KOOK_TEST_CONFIG
|
||||||
|
rm -f Kookfile
|
||||||
|
}
|
||||||
|
|
||||||
|
test_start() {
|
||||||
|
test_cleanup
|
||||||
|
TEST_TITLE="$*"
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "## TEST : $TEST_TITLE"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
test_start "Simple project listing"
|
||||||
|
kook project list $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Add project (explicit pah)"
|
||||||
|
kook project add kook-project $KOOK_OPTS --path . || fail
|
||||||
|
kook project list $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Add project (auto path)"
|
||||||
|
kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
kook project list $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Add and remove project"
|
||||||
|
kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
kook project list $KOOK_OPTS || fail
|
||||||
|
kook project rm kook-project $KOOK_OPTS || fail
|
||||||
|
kook project list $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Detect current project"
|
||||||
|
kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
kook project list $KOOK_OPTS || fail
|
||||||
|
kook project detect $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Simple view listing (explicit project)"
|
||||||
|
kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
kook view list $KOOK_OPTS --project kook-project || fail
|
||||||
|
|
||||||
|
#test_start "Simple view listing (implicit project)"
|
||||||
|
#kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
#kook view list $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Fire a project with no view"
|
||||||
|
kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
kook view list $KOOK_OPTS || fail
|
||||||
|
kook fire kook-project $KOOK_OPTS || fail
|
||||||
|
|
||||||
|
test_start "Add a project with a view (explicit project)"
|
||||||
|
kook project add kook-project $KOOK_OPTS || fail
|
||||||
|
kook view add root $KOOK_OPTS --project kook-project || fail
|
||||||
|
kook view list $KOOK_OPTS --project kook-project || fail
|
||||||
|
|
||||||
|
#test_cleanup
|
Loading…
Reference in a new issue