diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..c2d147d2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "public/s/js/jquery/plugins/jquery-form2xml"] + path = public/s/js/jquery/plugins/jquery-form2xml + url = git@github.com:docunext/jquery-form2xml.git diff --git a/README.markdown b/README.markdown index aadc5555..154e3b28 100644 --- a/README.markdown +++ b/README.markdown @@ -1,31 +1,133 @@ +<<<<<<< .merge_file_YFuwYZ +git-wiki +======== +======= +# git-wiki fork: + +## added features +- nested pages +- double click page to edit +- instant preview while editing +- save and continue editing + +## notable changes +- /pagename/edit is not /pagename?edit=1 + +## future features +- deleting pages +- restoring deleted pages +- moving pages +- shared sub-wiki's using submodules +- log / history / diff view + git-wiki: because who needs cool names when you use git? ======================================================== +>>>>>>> .merge_file_6bMFZW + +git-wiki is a wiki that relies on git to keep pages' history and +[Sinatra][] to serve them. This geek brain overlay system aims to +replace trac (wiki and ticket system), a CMS and sticky notes. + +Features of this fork (by geekQ) +--------------------- + +### Support for images + +You can add images to `/img` folder of your git repository. Subfolders +are also supported. At least gif, png and jpg supported - content type +is set automatically by Sinatra. You can reference the images then from +your wiki pages like `![My picture](/img/2009/my_picture.jpg)` + +No web interface at this time - use `git commit`. + + +### Custom h1 header + +If your wiki page contains a markdown h1 header, then this one is used +on the page. If not, then h1 is created out of the file name (as in +original git-wiki). + + +### Integrated TODO list(s) + +Just write TODO or DONE at the beginning of a line with task you would +like to remember. + + +#### Inclusion -git-wiki is a wiki that relies on git to keep pages' history -and [Sinatra][] to serve them. +You can include tasks from other wiki pages. So it is possible to have +one separate page per project, e.g. ProjectGitWiki, ProjectWorkflow and +to aggregate all coding tasks on one, say ContextCoding page with +`INCLUDE project:GitWiki`, `INCLUDE project:Workflow`. -I wrote git-wiki as a quick and dirty hack, mostly to play with Sinatra. -It turned out that Sinatra is an awesome little web framework and that this -hack isn't as useless as I first though since I now use it daily. +You can also reference other contexts with `INCLUDE context:AtHome`. -However, it is definitely not feature rich and will probably never be because -I mostly use it as a web frontend for `git`, `ls` and `vim`. +Recursion can be turned on with `INCLUDE context:AtHome recursive:true`. +It is off by default. + +You can also reference a source on the web. I prefer to manage my tasks +related to git-wiki development in this README file. So on my +ContextCoding page I have following reference: `INCLUDE +http://github.com/geekq/git-wiki/raw/master/README.markdown` + +* DONE: include via http +* DONE: recursive inclusion +* DONE: mark included tasks in special way +* DONE: switch recursion on or off +* DONE: avoid endless recursion by saving a list of visited nodes +* TODO: include a task list filtered by tagged value, e.g. `TASKS context:home` should list all the tasks for the specified context. +* DONE: allow optional asterisk in front of TODO +* TODO: group included lists by project +* TODO: merge and resort tasks from subsequent INCLUDE statements +* DONE: gather all tasks from all pages with `INCLUDE wiki:all` +* TODO: gather all the remaining (not referenced) tasks into `task inventory` page + +### No wiki words + +For a hacker the wiki words is more a distraction than a help. Example: +if I mention ActiveRecord, than it should not link to the wiki article +ActiveRecord but appear as it is. + +* DONE: do not rely on wiki words + +### Other plans + +* TODO: keyboard short cuts for edit and saving +* TODO: check dead links +* TODO: search engine +* IDEA: presentation system - markdown + my S5 alternative +* IDEA: support for attachments +* IDEA: support for deeper Wiki page folder structure +* IDEA: support for special programmed pages - via haml or liquid template engine -If you want history, search, etc. you should look at other people's [forks][], -especially [al3x][]'s one. Install ------- -The fellowing [gems][] are required to run git-wiki: +The following [gems][] are required to run git-wiki: - [Sinatra][] - [mojombo-grit][] - [HAML][] - [RDiscount][] +- [RestClient][] -Run with `mkdir ~/wiki && (cd ~/wiki && git init) && ./run.ru -sthin -p4567` -and point your browser at . Enjoy! +## Setup: +`mkdir ~/wiki && (cd ~/wiki && git init)` `./run.ru -sthin -p4567` + +then just point your browser at and you're done. Enjoy! + +<<<<<<< .merge_file_YFuwYZ +======= +## Setup: +`mkdir ~/wiki && (cd ~/wiki && git init)` `./run.ru -sthin -p4567` + +then just point your browser at and you're done. Enjoy! + +>>>>>>> .merge_file_6bMFZW +### Note: +if you're using passenger you'll want to symlink git_wiki/public into the repo's root directory See also -------- @@ -43,6 +145,7 @@ See also [mojombo-grit]: http://github.com/mojombo/grit [HAML]: http://haml.hamptoncatlin.com [RDiscount]: http://github.com/rtomayko/rdiscount + [RestClient]: http://github.com/archiloque/rest-client [tip]: http://wiki.infogami.com/using_lynx_&_vim_with_infogami [WiGit]: http://el-tramo.be/software/wigit [ikiwiki]: http://ikiwiki.info @@ -84,17 +187,21 @@ then sync your changes back when you're done.

Git is the next Unix

-Licence -------- - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2008 Simon Rozet - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. - - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 0. You just DO WHAT THE FUCK YOU WANT TO. +MIT license +----------- +Copyright (c) 2009 Vladimir Dobriakov, vladimir.dobriakov@innoq.com + +Copyright (c) Simon Rozet + +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. + diff --git a/config.ru b/config.ru new file mode 100644 index 00000000..b071e247 --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require "rubygems" +require File.dirname(__FILE__) + "/git-wiki" + +run GitWiki.new(File.expand_path("~/wiki"), ".markdown", "Home") \ No newline at end of file diff --git a/git-wiki.rb b/git-wiki.rb old mode 100755 new mode 100644 index aad7d1cc..f4b7393c --- a/git-wiki.rb +++ b/git-wiki.rb @@ -1,7 +1,12 @@ require "sinatra/base" require "haml" +require "sass" require "grit" require "rdiscount" +require 'net/ssh' + +require_relative "./git_wiki/page_not_found" +require_relative "./git_wiki/page" module GitWiki class << self @@ -16,127 +21,28 @@ def self.new(repository, extension, homepage) App end - class PageNotFound < Sinatra::NotFound - attr_reader :name - - def initialize(name) - @name = name - end - end - - class Page - def self.find_all - return [] if repository.tree.contents.empty? - repository.tree.contents.collect { |blob| new(blob) } - end - - def self.find(name) - page_blob = find_blob(name) - raise PageNotFound.new(name) unless page_blob - new(page_blob) - end - - def self.find_or_create(name) - find(name) - rescue PageNotFound - new(create_blob_for(name)) - end - - def self.css_class_for(name) - find(name) - "exists" - rescue PageNotFound - "unknown" - end - - def self.repository - GitWiki.repository || raise - end - def self.extension - GitWiki.extension || raise - end - - def self.find_blob(page_name) - repository.tree/(page_name + extension) - end - private_class_method :find_blob - - def self.create_blob_for(page_name) - Grit::Blob.create(repository, { - :name => page_name + extension, - :data => "" - }) - end - private_class_method :create_blob_for - - def initialize(blob) - @blob = blob - end - - def to_html - RDiscount.new(wiki_link(content)).to_html - end - - def to_s - name - end - - def new? - @blob.id.nil? - end - - def name - @blob.name.gsub(/#{File.extname(@blob.name)}$/, '') - end - - def content - @blob.data - end - - def update_content(new_content) - return if new_content == content - File.open(file_name, "w") { |f| f << new_content } - add_to_index_and_commit! - end - - private - def add_to_index_and_commit! - Dir.chdir(self.class.repository.working_dir) { - self.class.repository.add(@blob.name) - } - self.class.repository.commit_index(commit_message) - end - - def file_name - File.join(self.class.repository.working_dir, name + self.class.extension) - end - - def commit_message - new? ? "Created #{name}" : "Updated #{name}" - end - - def wiki_link(str) - str.gsub(/([A-Z][a-z]+[A-Z][A-Za-z0-9]+)/) { |page| - %Q{#{page}} - } - end - end class App < Sinatra::Base + set :public, File.dirname(__FILE__) + '/public' + set :static, true set :app_file, __FILE__ + set :user, 'albertlash' + set :host, '192.168.8.2' set :haml, { :format => :html5, :attr_wrapper => '"' } - use_in_file_templates! error PageNotFound do page = request.env["sinatra.error"].name - redirect "/#{page}/edit" + redirect "/#{page}?edit=1" end before do - content_type "text/html", :charset => "utf-8" + end + + get "/styles.css" do + content_type "text/css", :charset => "utf-8" + sass :styles end get "/" do @@ -144,77 +50,84 @@ class App < Sinatra::Base end get "/pages" do + @exclude = ['.gitignore','conf/cyberpulpit','conf/greencomputing','conf/hungryblogger','conf/informedblogging','conf/informedrealestate','conf/mmwiki','conf/neocarz','conf/neofilmz','conf/nexista','conf/nodows','conf/pbooks','conf/sbinfo','conf/telecomrebirth'] + @exclude << 'templates/page' + @exclude << 'templates/footer' @pages = Page.find_all + @pages.delete_if {|page| @exclude.include?(page.name) } haml :list end - get "/:page/edit" do - @page = Page.find_or_create(params[:page]) - haml :edit + get "/commits" do + @commits = Page.history + haml :commits + end + get "/commit-:wiki" do + host = settings.host + stdout = '' << host << "\n" + Net::SSH.start(host, settings.user) do |ssh| + ssh.exec!("cd /var/www/svxwikis && git pull && ikiwiki --setup /var/www/svxwikis/conf/#{params[:wiki]}.setup --rebuild") do |channel, stream, data| + stdout << data if stream == :stdout + end + end + @publish = '
'+stdout+'
' + haml :publish end - get "/:page" do - @page = Page.find(params[:page]) - haml :show + + #get "/:page/history" do + # @page = Page.history + # haml :history + #end + + get "/*" do + path = params[:splat].join('/') + if not params[:edit].nil? + @page = Page.find_or_create(path) + haml :edit + else + @page = Page.find(path) + haml :show + end end - post "/:page" do - @page = Page.find_or_create(params[:page]) + post "/*" do + path = params[:splat].join('/') + @page = Page.find_or_create(path) @page.update_content(params[:body]) redirect "/#{@page}" end + private def title(title=nil) - @title = title.to_s unless title.nil? + @title = title.to_s.gsub('_',' ').gsub(/\b\w+/){$&.capitalize} unless title.nil? @title end + def breadcrumbs(title=nil) + #@title = title.to_s.gsub('_',' ').gsub(/\b\w+/){$&.capitalize} unless title.nil? + unless title.nil? + @bc = title.to_s + if @bc.include?('/') + @breadc = '' + @bc = @bc.split('/').map! do |path| + folder_name = path.gsub('_',' ').gsub(/\b\w+/){$&.capitalize} + if @breadc.empty? + path = path + '/index' + else + @breadc.gsub!('/index','') + end + @breadc << '/' << path + %Q{#{folder_name}} + end.join('/') + end + end + @bc + end def list_item(page) - %Q{#{page.name}} + title = page.name.gsub('_',' ').gsub(/\b\w+/){$&.capitalize} + %Q{#{title}} end end end - -__END__ -@@ layout -!!! -%html - %head - %title= title - %body - %ul - %li - %a{ :href => "/#{GitWiki.homepage}" } Home - %li - %a{ :href => "/pages" } All pages - #content= yield - -@@ show -- title @page.name -#edit - %a{:href => "/#{@page}/edit"} Edit this page -%h1= title -#content - ~"#{@page.to_html}" - -@@ edit -- title "Editing #{@page.name}" -%h1= title -%form{:method => 'POST', :action => "/#{@page}"} - %p - %textarea{:name => 'body', :rows => 30, :style => "width: 100%"}= @page.content - %p - %input.submit{:type => :submit, :value => "Save as the newest version"} - or - %a.cancel{:href=>"/#{@page}"} cancel - -@@ list -- title "Listing pages" -%h1 All pages -- if @pages.empty? - %p No pages found. -- else - %ul#list - - @pages.each do |page| - %li= list_item(page) diff --git a/git_wiki/app.rb b/git_wiki/app.rb new file mode 100644 index 00000000..f1399e4c --- /dev/null +++ b/git_wiki/app.rb @@ -0,0 +1,56 @@ +module GitWiki + class App < Sinatra::Base + enable :static + set :public, Proc.new { File.join(root, "public") } + set :app_file, __FILE__ + set :haml, { :format => :html5, + :attr_wrapper => '"' } + + error PageNotFound do + page = request.env["sinatra.error"].name + redirect "/#{page}?edit=1" + end + + before do + content_type "text/html", :charset => "utf-8" + @page_class = []; + end + + get "/stylesheets/application.css" do + content_type "text/css; charset=utf-8", :charset => "utf-8" + sass :"application" + end + + post "/preview" do + RDiscount.new(params[:body]).to_html + end + + get "/" do + redirect "/" + GitWiki.homepage + end + + get "/pages" do + @pages = Page.find_all + haml :list + end + + get "/*" do + path = params[:splat].join('/') + if not params[:edit].nil? + @page = Page.find_or_create(path) + haml :edit + else + @page = Page.find(path) + haml :show + end + end + + post "/*" do + path = params[:splat].join('/') + @page = Page.find_or_create(path) + @page.update_content(params[:body]) + redirect "/#{@page}" + end + + end +end \ No newline at end of file diff --git a/git_wiki/page.rb b/git_wiki/page.rb new file mode 100644 index 00000000..c9ff2d95 --- /dev/null +++ b/git_wiki/page.rb @@ -0,0 +1,164 @@ +module GitWiki + class Page + def self.find_all + return [] if repository.tree.contents.empty? + + all_blobs = collect_blobs_from_tree(repository.tree) + + all_blobs.flatten.collect do |blob| + new(blob) + end + end + + def self.collect_blobs_from_tree(tree, path=nil) + path = (path.nil? || tree.name.nil?) ? '' : path+'/'+tree.name + tree.contents.inject([]) do |blobs, file| + if file.is_a? Grit::Blob + add_path_to_blob(file, path+'/'+file.name) + blobs.push file + elsif file.is_a? Grit::Tree + blobs.concat collect_blobs_from_tree(file, path) + end + blobs + end + end + + def self.find(name) + page_blob = find_blob(name) + raise PageNotFound.new(name) unless page_blob + new(page_blob) + end + + def self.find_or_create(name) + find(name) + rescue PageNotFound + new(create_blob_for(name)) + end + + def self.css_class_for(name) + find(name) + "exists" + rescue PageNotFound + "unknown" + end + + def self.history + repository.commits + end + + def self.repository + GitWiki.repository || raise + end + + def self.extension + GitWiki.extension || raise + end + + def self.find_blob(page_name) + blob = repository.tree/(page_name + extension) + add_path_to_blob(blob, page_name + extension) if blob + blob + end + private_class_method :find_blob + + def self.add_path_to_blob(blob, path) + blob.instance_eval do + def path + @path + end + def path=(new_path) + @path = new_path + end + end + blob.path = path + end + private_class_method :add_path_to_blob + + def self.create_blob_for(page_name) + blob = Grit::Blob.create(repository, { + :name => page_name + extension, + :data => "" + }) + add_path_to_blob(blob, page_name + extension) if blob + blob + end + private_class_method :create_blob_for + + def initialize(blob) + @blob = blob + end + + def to_html + RDiscount.new(wiki_link(content)).to_html + end + + def to_s + name + end + + def new? + @blob.id.nil? + end + + def name + @blob.path.gsub(/#{File.extname(@blob.name)}$/, '').gsub(/^\//,'') + end + + def short_name + File.basename(@blob.name).gsub(/#{File.extname(@blob.name)}$/, '') + end + + def parent_directories + File.dirname(name).split(/\//).inject([[],[]]){ |collection, dirname| + parents, paths = collection + parents.push(dirname) + paths.push(parents.join('/')) + [parents, paths] + }[1] + end + + def content + @blob.data + end + + def update_content(new_content) + return if new_content == content + system("mkdir -p '#{File.dirname(file_name)}'"); + File.open(file_name, "w") { |f| f << new_content } + add_to_index_and_commit! + end + + private + def add_to_index_and_commit! + Dir.chdir(self.class.repository.working_dir) { + self.class.repository.add(@blob.path) + } + self.class.repository.commit_index(commit_message) + end + + def file_name + File.join(self.class.repository.working_dir, name + self.class.extension) + end + + def commit_message + new? ? "Created #{name}" : "Updated #{name}" + end + + def wiki_link(str) + str.gsub(/\[\[([^\]]+\]\])/) { |page| + filename = page.downcase.gsub('[','').gsub(']','').gsub(/[^a-z0-9:\/\.]/,'_') + if filename =~ /^\// + wiki = file_name.gsub(self.class.repository.working_dir,'').split('/')[1] + file = wiki + filename + filename = '/' + file + else + file = File.expand_path(File.dirname(file_name) + '/' + filename) + file.gsub!(self.class.repository.working_dir+'/','') + end + linktext = page.gsub('[','').gsub(']','').split('/').pop().capitalize(); + %Q{#{linktext}} + } + end + end +end \ No newline at end of file diff --git a/git_wiki/page_not_found.rb b/git_wiki/page_not_found.rb new file mode 100644 index 00000000..d63cbffa --- /dev/null +++ b/git_wiki/page_not_found.rb @@ -0,0 +1,9 @@ +module GitWiki + class PageNotFound < Sinatra::NotFound + attr_reader :name + + def initialize(name) + @name = name + end + end +end \ No newline at end of file diff --git a/ikiwikis.ru b/ikiwikis.ru new file mode 100755 index 00000000..bb828151 --- /dev/null +++ b/ikiwikis.ru @@ -0,0 +1,5 @@ +#!/home/albertlash/.rbenv/versions/1.9.3-rc1/bin/rackup +require "./git-wiki" + +run GitWiki.new("/home/albertlash/savonix/wikis", + ARGV[2] || ".mdwn", ARGV[3] || "index") diff --git a/public/s/css/yui.reset.css b/public/s/css/yui.reset.css new file mode 100644 index 00000000..47844f75 --- /dev/null +++ b/public/s/css/yui.reset.css @@ -0,0 +1,7 @@ +/* +Copyright (c) 2009, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.net/yui/license.txt +version: 2.8.0r4 +*/ +html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;} diff --git a/run.ru b/run.ru index 664eb858..53c09e2a 100755 --- a/run.ru +++ b/run.ru @@ -1,5 +1,5 @@ -#!/usr/bin/env rackup +#!/usr/bin/rackup1.8 require File.dirname(__FILE__) + "/git-wiki" -run GitWiki.new(File.expand_path(ARGV[1] || "~/wiki"), - ARGV[2] || ".markdown", ARGV[3] || "Home") +run GitWiki.new(File.expand_path("~/nudocs/mntdocs/"), + ARGV[2] || ".mdwn", ARGV[3] || "Home") diff --git a/views/commits.haml b/views/commits.haml new file mode 100644 index 00000000..f868062e --- /dev/null +++ b/views/commits.haml @@ -0,0 +1,8 @@ +- title "Listing commits" +%h1 All commits +- if @commits.empty? + %p No commits found. +- else + %ul#list + - @commits.each do |commit| + %li= commit.id << " " << commit.authored_date.to_s diff --git a/views/edit.haml b/views/edit.haml new file mode 100644 index 00000000..b3e5704b --- /dev/null +++ b/views/edit.haml @@ -0,0 +1,9 @@ +- title "Editing #{@page.name}" +%h1= title +%form{:method => 'POST', :action => "/#{@page}"} + %p + %textarea{:name => 'body', :rows => 30, :style => "width: 100%"}= @page.content + %p + %input.submit{:type => :submit, :value => "Save as the newest version"} + or + %a.cancel{:href=>"/#{@page}"} cancel diff --git a/views/layout.haml b/views/layout.haml new file mode 100644 index 00000000..549f577d --- /dev/null +++ b/views/layout.haml @@ -0,0 +1,16 @@ +!!! +%html + %head + %title= title + %script{ :type=> "text/javascript", :src=> "http://www-01.evenserver.com/s/js/jquery/jquery-1.4.2.min.js" } + %link{ :rel=> "stylesheet", :type=> "text/css", :href=> "/s/css/yui.reset.css" } + %link{ :href=> "/styles.css", :media=> 'all', :type=> "text/css", :rel=> "stylesheet" } + %body + %ul{:id=> 'header-menu'} + %li + %a{ :href => "/#{GitWiki.homepage}" } Home + %li + %a{ :href => "/pages" } All pages + %li + %a{ :href => "/commits" } Commits + #container= yield \ No newline at end of file diff --git a/views/list.haml b/views/list.haml new file mode 100644 index 00000000..d8813524 --- /dev/null +++ b/views/list.haml @@ -0,0 +1,9 @@ +- title "Listing pages" +%h1 All #{@pages.count} pages +- if @pages.empty? + %p No pages found. +- else + %ul#list + - @pages.each do |page| + %li= list_item(page) + %p #{@pages.count} pages \ No newline at end of file diff --git a/views/publish.haml b/views/publish.haml new file mode 100644 index 00000000..5808f75c --- /dev/null +++ b/views/publish.haml @@ -0,0 +1,3 @@ +- title "Publish" +#content + ~"#{@publish}" \ No newline at end of file diff --git a/views/show.haml b/views/show.haml new file mode 100644 index 00000000..a6bfd22f --- /dev/null +++ b/views/show.haml @@ -0,0 +1,10 @@ +- title @page.name +#page-controls + %ul + %li + %a{:href => "/#{@page}?edit=1"} Edit this page + %li + %a{:href => "/#{@page}/history"} History +%h1= breadcrumbs(@page.name) +#content + ~"#{@page.to_html}" \ No newline at end of file diff --git a/views/styles.sass b/views/styles.sass new file mode 100644 index 00000000..db289097 --- /dev/null +++ b/views/styles.sass @@ -0,0 +1,31 @@ +h1 + :font-size 120% + :margin-top 1em + +h2 + :font-size 110% + :margin-top 1em + +h3 + :font-size 105% + :margin-top 1em + + +div + :padding 10px !important + +#header-menu li, #page-controls li + :display inline + +#content ul li + :list-style-type disc + +#content ul + :margin 2em + +.unknown + :color red + +ol li + :margin-left 2em + :list-style-type decimal