@@ -5,19 +5,20 @@ parent=parent[n];}} | |||||
wn.provide('wn.settings');wn.provide('wn.ui');wn.xmlhttp={request:function(){if(window.XMLHttpRequest) | wn.provide('wn.settings');wn.provide('wn.ui');wn.xmlhttp={request:function(){if(window.XMLHttpRequest) | ||||
return new XMLHttpRequest();else if(window.ActiveXObject) | return new XMLHttpRequest();else if(window.ActiveXObject) | ||||
return new ActiveXObject("MsXml2.XmlHttp");},complete:function(req,callback,url){if(req.status==200||req.status==304){callback(req.responseText);}else{alert(url+' request error: '+req.statusText+' ('+req.status+')');}},get:function(url,callback,args,async){if(async===null)async=true;var req=wn.xmlhttp.request();req.onreadystatechange=function(){if(req.readyState==4){wn.xmlhttp.complete(req,callback,url)}} | return new ActiveXObject("MsXml2.XmlHttp");},complete:function(req,callback,url){if(req.status==200||req.status==304){callback(req.responseText);}else{alert(url+' request error: '+req.statusText+' ('+req.status+')');}},get:function(url,callback,args,async){if(async===null)async=true;var req=wn.xmlhttp.request();req.onreadystatechange=function(){if(req.readyState==4){wn.xmlhttp.complete(req,callback,url)}} | ||||
var u=args?(url+'?'+args):url;req.open('GET',u,async);req.send(null);if(!async){wn.xmlhttp.complete(req,callback,url)}}} | |||||
var sep=(args.indexOf('?')==-1?'?':'&');var u=args?(url+sep+args):url;req.open('GET',u,async);req.send(null);if(!async){wn.xmlhttp.complete(req,callback,url)}}} | |||||
wn.versions={is_latest:function(){if(window._version_number==(localStorage?localStorage['_version_number']:null)){return true;} | wn.versions={is_latest:function(){if(window._version_number==(localStorage?localStorage['_version_number']:null)){return true;} | ||||
return false;},get_diff:function(){if(!localStorage)return;wn.xmlhttp.get('index.cgi',function(txt){r=JSON.parse(txt);if(r.exc){alert(r.exc);} | return false;},get_diff:function(){if(!localStorage)return;wn.xmlhttp.get('index.cgi',function(txt){r=JSON.parse(txt);if(r.exc){alert(r.exc);} | ||||
wn.versions.set(r.message);},'cmd=get_diff&version_number='+localStorage['_version_number'],false);},set:function(diff){for(var i=0;i<diff.length;i++){localStorage.removeItem(diff[i]);} | wn.versions.set(r.message);},'cmd=get_diff&version_number='+localStorage['_version_number'],false);},set:function(diff){for(var i=0;i<diff.length;i++){localStorage.removeItem(diff[i]);} | ||||
localStorage['_version_number']=_version_number;},check:function(){if(localStorage&&!localStorage['_version_number']){localStorage['_version_number']=_version_number;return;} | localStorage['_version_number']=_version_number;},check:function(){if(localStorage&&!localStorage['_version_number']){localStorage['_version_number']=_version_number;return;} | ||||
if(!wn.versions.is_latest())wn.versions.get_diff();}} | if(!wn.versions.is_latest())wn.versions.get_diff();}} | ||||
wn.assets={executed_:{},exists:function(src){if('localStorage'in window&&localStorage.getItem(src)) | wn.assets={executed_:{},exists:function(src){if('localStorage'in window&&localStorage.getItem(src)) | ||||
return true},add:function(src,txt){if('localStorage'in window){localStorage.setItem(src,txt);}},get:function(src){return localStorage.getItem(src);},extn:function(src){return src.split('.').slice(-1)[0];},html_src:function(src){if(src.indexOf('/')!=-1){var t=src.split('/').slice(0,-1);t.push('src');t=t.join('/')+'/'+a.split('/').slice(-1)[0];}else{var t='src/'+src;} | |||||
return true},add:function(src,txt){if('localStorage'in window){localStorage.setItem(src,txt);}},get:function(src){return localStorage.getItem(src);},extn:function(src){if(src.indexOf('?')!=-1){src=src.split('?').slice(-1)[0];} | |||||
return src.split('.').slice(-1)[0];},html_src:function(src){if(src.indexOf('/')!=-1){var t=src.split('/').slice(0,-1);t.push('src');t=t.join('/')+'/'+a.split('/').slice(-1)[0];}else{var t='src/'+src;} | |||||
return t;},load:function(src){var t=wn.assets.extn(src)=='html'?wn.assets.html_src(src):src;wn.xmlhttp.get(t,function(txt){wn.assets.add(src,txt);},'q='&Math.floor(Math.random()*1000),false)},execute:function(src){if(!wn.assets.exists(src)){wn.assets.load(src);} | return t;},load:function(src){var t=wn.assets.extn(src)=='html'?wn.assets.html_src(src):src;wn.xmlhttp.get(t,function(txt){wn.assets.add(src,txt);},'q='&Math.floor(Math.random()*1000),false)},execute:function(src){if(!wn.assets.exists(src)){wn.assets.load(src);} | ||||
var type=wn.assets.extn(src);if(wn.assets.handler[type]){wn.assets.handler[type](wn.assets.get(src),src);wn.assets.executed_[src]=1;}},handler:{js:function(txt,src){wn.dom.eval(txt);},css:function(txt,src){var se=document.createElement('style');se.type="text/css";if(se.styleSheet){se.styleSheet.cssText=txt;}else{se.appendChild(document.createTextNode(txt));} | var type=wn.assets.extn(src);if(wn.assets.handler[type]){wn.assets.handler[type](wn.assets.get(src),src);wn.assets.executed_[src]=1;}},handler:{js:function(txt,src){wn.dom.eval(txt);},css:function(txt,src){var se=document.createElement('style');se.type="text/css";if(se.styleSheet){se.styleSheet.cssText=txt;}else{se.appendChild(document.createTextNode(txt));} | ||||
document.getElementsByTagName('head')[0].appendChild(se);},html:function(txt,src){var page=wn.dom.add($('.outer .inner').get(0),'div','content',null,txt);page.setAttribute("_src",src);}}} | |||||
document.getElementsByTagName('head')[0].appendChild(se);},html:function(txt,src){var page=wn.dom.add($('.outer .inner').get(0),'div','content',null,txt);page.setAttribute("_src",src);},cgi:function(txt,src){wn.dom.eval(txt)}}} | |||||
wn.require=function(items){if(typeof items==="string"){items=[items];} | wn.require=function(items){if(typeof items==="string"){items=[items];} | ||||
var l=items.length;for(var i=0;i<l;i++){var src=items[i];if(!(src in wn.assets.executed_)){wn.assets.execute(src)}}} | |||||
var l=items.length;for(var i=0;i<l;i++){var src=items[i];if(!(src in wn.assets.executed_)){wn.assets.execute(src);}}} | |||||
wn.provide('wn.dom');wn.dom.by_id=function(id){return document.getElementById(id);} | wn.provide('wn.dom');wn.dom.by_id=function(id){return document.getElementById(id);} | ||||
wn.dom.eval=function(txt){var el=document.createElement('script');el.appendChild(document.createTextNode(txt));document.getElementsByTagName('head')[0].appendChild(el);} | wn.dom.eval=function(txt){var el=document.createElement('script');el.appendChild(document.createTextNode(txt));document.getElementsByTagName('head')[0].appendChild(el);} | ||||
wn.dom.add=function(parent,newtag,className,cs,innerHTML,onclick){if(parent&&parent.substr)parent=wn.dom.by_id(parent);var c=document.createElement(newtag);if(parent) | wn.dom.add=function(parent,newtag,className,cs,innerHTML,onclick){if(parent&&parent.substr)parent=wn.dom.by_id(parent);var c=document.createElement(newtag);if(parent) | ||||
@@ -71,7 +71,7 @@ Dialog.prototype.make_row = function(d) { | |||||
c1.innerHTML = d[1]; | c1.innerHTML = d[1]; | ||||
c2.style.overflow = 'auto'; | c2.style.overflow = 'auto'; | ||||
this.widgets[d[1]] = $a_input(c2, 'text'); | this.widgets[d[1]] = $a_input(c2, 'text'); | ||||
if(d[2])$a(c2, 'div', 'comment').innerHTML = d[2]; | |||||
if(d[2])$a(c2, 'div', 'field_description').innerHTML = d[2]; | |||||
} | } | ||||
else if(d[0]=='Link') { | else if(d[0]=='Link') { | ||||
c1.innerHTML = d[1]; | c1.innerHTML = d[1]; | ||||
@@ -93,20 +93,20 @@ Dialog.prototype.make_row = function(d) { | |||||
c1.innerHTML = d[1]; | c1.innerHTML = d[1]; | ||||
c2.style.overflow = 'auto'; | c2.style.overflow = 'auto'; | ||||
this.widgets[d[1]] = $a_input(c2, 'password'); | this.widgets[d[1]] = $a_input(c2, 'password'); | ||||
if(d[3])$a(c2, 'div', 'comment').innerHTML = d[3]; | |||||
if(d[3])$a(c2, 'div', 'field_description').innerHTML = d[3]; | |||||
} | } | ||||
else if(d[0]=='Select') { | else if(d[0]=='Select') { | ||||
c1.innerHTML = d[1]; | c1.innerHTML = d[1]; | ||||
this.widgets[d[1]] = $a(c2, 'select', '', {width:'160px'}) | this.widgets[d[1]] = $a(c2, 'select', '', {width:'160px'}) | ||||
if(d[2])$a(c2, 'div', 'comment').innerHTML = d[2]; | |||||
if(d[2])$a(c2, 'div', 'field_description').innerHTML = d[2]; | |||||
if(d[3])add_sel_options(this.widgets[d[1]], d[3], d[3][0]); | if(d[3])add_sel_options(this.widgets[d[1]], d[3], d[3][0]); | ||||
} | } | ||||
else if(d[0]=='Text') { | else if(d[0]=='Text') { | ||||
c1.innerHTML = d[1]; | c1.innerHTML = d[1]; | ||||
c2.style.overflow = 'auto'; | c2.style.overflow = 'auto'; | ||||
this.widgets[d[1]] = $a(c2, 'textarea'); | this.widgets[d[1]] = $a(c2, 'textarea'); | ||||
if(d[2])$a(c2, 'div', 'comment').innerHTML = d[2]; | |||||
if(d[2])$a(c2, 'div', 'field_description').innerHTML = d[2]; | |||||
} | } | ||||
else if(d[0]=='Button') { | else if(d[0]=='Button') { | ||||
c2.style.height = '32px'; | c2.style.height = '32px'; | ||||
@@ -329,13 +329,13 @@ Dialog.prototype.make_row=function(d){var me=this;this.rows[d[1]]=$a(this.body,' | |||||
$t(c1,d[1]);} | $t(c1,d[1]);} | ||||
if(d[0]=='HTML'){if(d[2])row.innerHTML=d[2];this.widgets[d[1]]=row;} | if(d[0]=='HTML'){if(d[2])row.innerHTML=d[2];this.widgets[d[1]]=row;} | ||||
else if(d[0]=='Check'){var i=$a_input(c2,'checkbox','',{width:'20px'});c1.innerHTML=d[1];this.widgets[d[1]]=i;} | else if(d[0]=='Check'){var i=$a_input(c2,'checkbox','',{width:'20px'});c1.innerHTML=d[1];this.widgets[d[1]]=i;} | ||||
else if(d[0]=='Data'){c1.innerHTML=d[1];c2.style.overflow='auto';this.widgets[d[1]]=$a_input(c2,'text');if(d[2])$a(c2,'div','comment').innerHTML=d[2];} | |||||
else if(d[0]=='Data'){c1.innerHTML=d[1];c2.style.overflow='auto';this.widgets[d[1]]=$a_input(c2,'text');if(d[2])$a(c2,'div','field_description').innerHTML=d[2];} | |||||
else if(d[0]=='Link'){c1.innerHTML=d[1];var f=make_field({fieldtype:'Link','label':d[1],'options':d[2]},'',c2,this,0,1);f.not_in_form=1;f.dialog=this;f.refresh();this.widgets[d[1]]=f.input;} | else if(d[0]=='Link'){c1.innerHTML=d[1];var f=make_field({fieldtype:'Link','label':d[1],'options':d[2]},'',c2,this,0,1);f.not_in_form=1;f.dialog=this;f.refresh();this.widgets[d[1]]=f.input;} | ||||
else if(d[0]=='Date'){c1.innerHTML=d[1];var f=make_field({fieldtype:'Date','label':d[1],'options':d[2]},'',c2,this,0,1);f.not_in_form=1;f.refresh();f.dialog=this;this.widgets[d[1]]=f.input;} | else if(d[0]=='Date'){c1.innerHTML=d[1];var f=make_field({fieldtype:'Date','label':d[1],'options':d[2]},'',c2,this,0,1);f.not_in_form=1;f.refresh();f.dialog=this;this.widgets[d[1]]=f.input;} | ||||
else if(d[0]=='Password'){c1.innerHTML=d[1];c2.style.overflow='auto';this.widgets[d[1]]=$a_input(c2,'password');if(d[3])$a(c2,'div','comment').innerHTML=d[3];} | |||||
else if(d[0]=='Password'){c1.innerHTML=d[1];c2.style.overflow='auto';this.widgets[d[1]]=$a_input(c2,'password');if(d[3])$a(c2,'div','field_description').innerHTML=d[3];} | |||||
else if(d[0]=='Select'){c1.innerHTML=d[1];this.widgets[d[1]]=$a(c2,'select','',{width:'160px'}) | else if(d[0]=='Select'){c1.innerHTML=d[1];this.widgets[d[1]]=$a(c2,'select','',{width:'160px'}) | ||||
if(d[2])$a(c2,'div','comment').innerHTML=d[2];if(d[3])add_sel_options(this.widgets[d[1]],d[3],d[3][0]);} | |||||
else if(d[0]=='Text'){c1.innerHTML=d[1];c2.style.overflow='auto';this.widgets[d[1]]=$a(c2,'textarea');if(d[2])$a(c2,'div','comment').innerHTML=d[2];} | |||||
if(d[2])$a(c2,'div','field_description').innerHTML=d[2];if(d[3])add_sel_options(this.widgets[d[1]],d[3],d[3][0]);} | |||||
else if(d[0]=='Text'){c1.innerHTML=d[1];c2.style.overflow='auto';this.widgets[d[1]]=$a(c2,'textarea');if(d[2])$a(c2,'div','field_description').innerHTML=d[2];} | |||||
else if(d[0]=='Button'){c2.style.height='32px';c2.style.textAlign='right';var b=$btn(c2,d[1],function(btn){if(btn._onclick)btn._onclick(me)},null,null,1);b.dialog=me;if(d[2]){b._onclick=d[2];} | else if(d[0]=='Button'){c2.style.height='32px';c2.style.textAlign='right';var b=$btn(c2,d[1],function(btn){if(btn._onclick)btn._onclick(me)},null,null,1);b.dialog=me;if(d[2]){b._onclick=d[2];} | ||||
this.widgets[d[1]]=b;}} | this.widgets[d[1]]=b;}} | ||||
list_opts={cell_style:{padding:'3px 2px'},alt_cell_style:{},head_style:{height:'20px',overflow:'hidden',verticalAlign:'middle',fontWeight:'bold',padding:'1px',fontSize:'13px'},head_main_style:{padding:'0px'},hide_export:1,hide_print:1,hide_refresh:0,hide_rec_label:0,show_calc:1,show_empty_tab:0,no_border:1,append_records:1,table_width:null};function Listing(head_text,no_index,no_loading){wn.require('lib/js/legacy/widgets/form/fields.js');this.start=0;this.page_len=20;this.filters_per_line=7;this.cell_idx=0;this.head_text=head_text?head_text:'Result';this.keyword='records';this.no_index=no_index;this.underline=1;this.no_rec_message='No Result';this.show_cell=null;this.show_result=null;this.colnames=null;this.colwidths=null;this.coltypes=null;this.coloptions=null;this.filters={};this.sort_list={};this.sort_order_dict={};this.sort_heads={};this.is_std_query=false;this.server_call=null;this.no_loading=no_loading;this.opts=copy_dict(list_opts);} | list_opts={cell_style:{padding:'3px 2px'},alt_cell_style:{},head_style:{height:'20px',overflow:'hidden',verticalAlign:'middle',fontWeight:'bold',padding:'1px',fontSize:'13px'},head_main_style:{padding:'0px'},hide_export:1,hide_print:1,hide_refresh:0,hide_rec_label:0,show_calc:1,show_empty_tab:0,no_border:1,append_records:1,table_width:null};function Listing(head_text,no_index,no_loading){wn.require('lib/js/legacy/widgets/form/fields.js');this.start=0;this.page_len=20;this.filters_per_line=7;this.cell_idx=0;this.head_text=head_text?head_text:'Result';this.keyword='records';this.no_index=no_index;this.underline=1;this.no_rec_message='No Result';this.show_cell=null;this.show_result=null;this.colnames=null;this.colwidths=null;this.coltypes=null;this.coloptions=null;this.filters={};this.sort_list={};this.sort_order_dict={};this.sort_heads={};this.is_std_query=false;this.server_call=null;this.no_loading=no_loading;this.opts=copy_dict(list_opts);} | ||||
@@ -28,6 +28,9 @@ wn.assets = { | |||||
}, | }, | ||||
extn: function(src) { | extn: function(src) { | ||||
if(src.indexOf('?')!=-1) { | |||||
src = src.split('?').slice(-1)[0]; | |||||
} | |||||
return src.split('.').slice(-1)[0]; | return src.split('.').slice(-1)[0]; | ||||
}, | }, | ||||
@@ -45,6 +48,8 @@ wn.assets = { | |||||
// load an asset via | // load an asset via | ||||
// xmlhttp | // xmlhttp | ||||
load: function(src) { | load: function(src) { | ||||
// this is virtual page load, only get the the source | |||||
// *without* the template | |||||
var t = wn.assets.extn(src)=='html' ? wn.assets.html_src(src) : src; | var t = wn.assets.extn(src)=='html' ? wn.assets.html_src(src) : src; | ||||
wn.xmlhttp.get(t, function(txt) { | wn.xmlhttp.get(t, function(txt) { | ||||
@@ -86,6 +91,11 @@ wn.assets = { | |||||
// make the html content page | // make the html content page | ||||
var page = wn.dom.add($('.outer .inner').get(0), 'div', 'content', null, txt); | var page = wn.dom.add($('.outer .inner').get(0), 'div', 'content', null, txt); | ||||
page.setAttribute("_src", src); | page.setAttribute("_src", src); | ||||
}, | |||||
cgi: function(txt, src) { | |||||
// dynamic content, will return content as | |||||
// javascript | |||||
wn.dom.eval(txt) | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,4 +1,8 @@ | |||||
// require js file | // require js file | ||||
// items to be called by their direct names | |||||
// for handler functions | |||||
// wn.require('index.cgi?cmd=startup') | |||||
wn.require = function(items) { | wn.require = function(items) { | ||||
if(typeof items === "string") { | if(typeof items === "string") { | ||||
items = [items]; | items = [items]; | ||||
@@ -9,7 +13,7 @@ wn.require = function(items) { | |||||
var src = items[i]; | var src = items[i]; | ||||
if(!(src in wn.assets.executed_)) { | if(!(src in wn.assets.executed_)) { | ||||
// check if available in localstorage | // check if available in localstorage | ||||
wn.assets.execute(src) | |||||
wn.assets.execute(src); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -25,7 +25,14 @@ wn.xmlhttp = { | |||||
wn.xmlhttp.complete(req, callback, url) | wn.xmlhttp.complete(req, callback, url) | ||||
} | } | ||||
} | } | ||||
var u = args ? (url + '?' + args) : url; | |||||
// separator can be & or ? | |||||
// based on if there are already arguments | |||||
var sep = (args.indexOf('?')==-1 ? '?' : '&'); | |||||
// add arguments to url | |||||
var u = args ? (url + sep + args) : url; | |||||
// call the server | |||||
req.open('GET', u, async); | req.open('GET', u, async); | ||||
req.send(null); | req.send(null); | ||||
@@ -17,19 +17,13 @@ | |||||
must pull the latest .wnf db and merge | must pull the latest .wnf db and merge | ||||
versions-local.db is never commited in the global repository | versions-local.db is never commited in the global repository | ||||
TODO | |||||
- walk | |||||
- merge | |||||
- client | |||||
""" | """ | ||||
import unittest | import unittest | ||||
import os | import os | ||||
test_file = {'fname':'test.js', 'ftype':'js', 'content':'test_code', 'timestamp':'1100'} | test_file = {'fname':'test.js', 'ftype':'js', 'content':'test_code', 'timestamp':'1100'} | ||||
root_path = os.path.abspath(os.curdir) | |||||
root_path = os.curdir | |||||
def edit_file(): | def edit_file(): | ||||
# edit a file | # edit a file | ||||
@@ -50,18 +44,18 @@ verbose = False | |||||
class TestVC(unittest.TestCase): | class TestVC(unittest.TestCase): | ||||
def setUp(self): | def setUp(self): | ||||
self.vc = VersionControl() | |||||
self.vc = VersionControl(root_path, True) | |||||
self.vc.repo.setup() | self.vc.repo.setup() | ||||
def test_add(self): | def test_add(self): | ||||
self.vc.repo.add(**test_file) | |||||
ret = self.vc.repo.sql('select * from uncommitted', as_dict=1)[0] | |||||
self.assertTrue(ret==test_file) | |||||
self.vc.add(**test_file) | |||||
ret = self.vc.repo.sql('select * from uncommitted', as_dict=1)[0] | |||||
self.assertTrue(ret['content']==test_file['content']) | |||||
def test_commit(self): | def test_commit(self): | ||||
last_number = self.vc.repo.get_value('last_version_number') | last_number = self.vc.repo.get_value('last_version_number') | ||||
self.vc.repo.add(**test_file) | |||||
self.vc.repo.commit() | |||||
self.vc.add(**test_file) | |||||
self.vc.commit() | |||||
# test version | # test version | ||||
number = self.vc.repo.get_value('last_version_number') | number = self.vc.repo.get_value('last_version_number') | ||||
@@ -78,8 +72,8 @@ class TestVC(unittest.TestCase): | |||||
self.assertTrue(self.vc.repo.sql("select * from log where version=?", (version,))) | self.assertTrue(self.vc.repo.sql("select * from log where version=?", (version,))) | ||||
def test_diff(self): | def test_diff(self): | ||||
self.vc.repo.add(**test_file) | |||||
self.vc.repo.commit() | |||||
self.vc.add(**test_file) | |||||
self.vc.commit() | |||||
self.assertTrue(self.vc.repo.diff(None), ['test.js']) | self.assertTrue(self.vc.repo.diff(None), ['test.js']) | ||||
def test_walk(self): | def test_walk(self): | ||||
@@ -90,7 +84,7 @@ class TestVC(unittest.TestCase): | |||||
ret = self.vc.repo.sql("select * from uncommitted", as_dict=1) | ret = self.vc.repo.sql("select * from uncommitted", as_dict=1) | ||||
self.assertTrue(len(ret)>0) | self.assertTrue(len(ret)>0) | ||||
self.vc.repo.commit() | |||||
self.vc.commit() | |||||
p = edit_file() | p = edit_file() | ||||
# add | # add | ||||
@@ -103,19 +97,18 @@ class TestVC(unittest.TestCase): | |||||
def test_merge(self): | def test_merge(self): | ||||
self.vc.add_all() | self.vc.add_all() | ||||
self.vc.repo.commit() | |||||
self.vc.commit() | |||||
# write the file | # write the file | ||||
self.vc.repo.conn.commit() | self.vc.repo.conn.commit() | ||||
# make master (copy) | # make master (copy) | ||||
os.system('cp %s %s' % (os.path.join(root_path, 'versions-local.db'), os.path.join(root_path, 'versions-master.db'))) | |||||
self.vc.setup_master() | self.vc.setup_master() | ||||
p = edit_file() | p = edit_file() | ||||
self.vc.add_all() | self.vc.add_all() | ||||
self.vc.repo.commit() | |||||
self.vc.commit() | |||||
self.vc.merge(self.vc.repo, self.vc.master) | self.vc.merge(self.vc.repo, self.vc.master) | ||||
@@ -124,39 +117,66 @@ class TestVC(unittest.TestCase): | |||||
def tearDown(self): | def tearDown(self): | ||||
self.vc.close() | self.vc.close() | ||||
os.remove(self.vc.repo.db_path) | |||||
if os.path.exists(self.vc.local_db_name()): | |||||
os.remove(self.vc.local_db_name()) | |||||
if os.path.exists(self.vc.master_db_name()): | |||||
os.remove(self.vc.master_db_name()) | |||||
class VersionControl: | class VersionControl: | ||||
def __init__(self, root=None): | |||||
#self.master = Repository(self, 'versions-master.db') | |||||
def __init__(self, root=None, testing=False): | |||||
self.testing = testing | |||||
self.set_root(root) | self.set_root(root) | ||||
self.repo = Repository(self, 'versions-local.db') | |||||
self.repo = Repository(self, self.local_db_name()) | |||||
self.ignore_folders = ['.git', '.', '..'] | self.ignore_folders = ['.git', '.', '..'] | ||||
self.ignore_files = ['py', 'pyc', 'DS_Store', 'txt', 'db-journal', 'db'] | self.ignore_files = ['py', 'pyc', 'DS_Store', 'txt', 'db-journal', 'db'] | ||||
def local_db_name(self): | |||||
"""return local db name""" | |||||
return os.path.join(self.root_path, 'versions-local.db' + (self.testing and '.test' or '')) | |||||
def master_db_name(self): | |||||
"""return master db name""" | |||||
return os.path.join(self.root_path, 'versions-master.db' + (self.testing and '.test' or '')) | |||||
def setup_master(self): | def setup_master(self): | ||||
self.master = Repository(self, 'versions-master.db') | |||||
""" | |||||
setup master db from local (if not present) | |||||
""" | |||||
import os | |||||
if not os.path.exists(self.master_db_name()): | |||||
os.system('cp %s %s' % (self.local_db_name(), self.master_db_name())) | |||||
self.master = Repository(self, self.master_db_name()) | |||||
def set_root(self, path=None): | def set_root(self, path=None): | ||||
""" | """ | ||||
set / reset root and connect | set / reset root and connect | ||||
(the root path is the path of the folder) | (the root path is the path of the folder) | ||||
""" | """ | ||||
import os | |||||
if not path: | if not path: | ||||
raise Exception, 'path must be given' | |||||
path = os.path.abspath(os.path.curdir) | |||||
self.root_path = path | self.root_path = path | ||||
def relpath(self, fname): | |||||
""" | |||||
get relative path from root path | |||||
""" | |||||
import os | |||||
return os.path.relpath(fname, self.root_path) | |||||
def timestamp(self, path): | def timestamp(self, path): | ||||
""" | """ | ||||
returns timestamp | returns timestamp | ||||
""" | """ | ||||
import os | import os | ||||
return int(os.stat(path).st_mtime) | |||||
if os.path.exists(path): | |||||
return int(os.stat(path).st_mtime) | |||||
else: | |||||
return 0 | |||||
def add_all(self): | def add_all(self): | ||||
""" | """ | ||||
@@ -182,7 +202,7 @@ class VersionControl: | |||||
continue | continue | ||||
# file does not exist | # file does not exist | ||||
if not self.repo.exists(fpath): | |||||
if not self.exists(fpath): | |||||
if verbose: | if verbose: | ||||
print "%s added" % fpath | print "%s added" % fpath | ||||
self.repo.add(fpath) | self.repo.add(fpath) | ||||
@@ -217,16 +237,44 @@ class VersionControl: | |||||
target.add(**f) | target.add(**f) | ||||
target.commit(d[0]) | target.commit(d[0]) | ||||
""" | |||||
short hand | |||||
""" | |||||
def commit(self, version=None): | |||||
"""commit to local""" | |||||
self.repo.commit(version) | |||||
def add(self, **args): | |||||
"""add to local""" | |||||
self.repo.add(**args) | |||||
def remove(self, fname): | |||||
"""remove from local""" | |||||
self.repo.add(fname=fname, action='remove') | |||||
def exists(self, fname): | |||||
"""exists in local""" | |||||
return len(self.repo.sql("select fname from files where fname=?", (self.relpath(fname),))) | |||||
def get_file(self, fname): | |||||
"""return file""" | |||||
return self.repo.sql("select * from files where fname=?", (self.relpath(fname),), as_dict=1)[0] | |||||
def close(self): | def close(self): | ||||
self.repo.conn.commit() | self.repo.conn.commit() | ||||
self.repo.conn.close() | self.repo.conn.close() | ||||
class Repository: | class Repository: | ||||
def __init__(self, vc, fname = 'versions-local.db'): | |||||
def __init__(self, vc, fname): | |||||
self.vc = vc | self.vc = vc | ||||
import sqlite3 | import sqlite3 | ||||
self.db_path = os.path.join(self.vc.root_path, fname) | self.db_path = os.path.join(self.vc.root_path, fname) | ||||
self.conn = sqlite3.connect(self.db_path) | self.conn = sqlite3.connect(self.db_path) | ||||
self.cur = self.conn.cursor() | self.cur = self.conn.cursor() | ||||
@@ -238,7 +286,7 @@ class Repository: | |||||
print "setting up %s..." % self.db_path | print "setting up %s..." % self.db_path | ||||
self.cur.executescript(""" | self.cur.executescript(""" | ||||
create table properties(pkey primary key, value); | create table properties(pkey primary key, value); | ||||
create table uncommitted(fname primary key, ftype, content, timestamp); | |||||
create table uncommitted(fname primary key, ftype, content, timestamp, action); | |||||
create table files (fname primary key, ftype, content, timestamp, version); | create table files (fname primary key, ftype, content, timestamp, version); | ||||
create table log (fname, ftype, version); | create table log (fname, ftype, version); | ||||
create table versions (number integer primary key, version); | create table versions (number integer primary key, version); | ||||
@@ -277,22 +325,26 @@ class Repository: | |||||
self.sql("insert or replace into properties(pkey, value) values (?, ?)", (key,value)) | self.sql("insert or replace into properties(pkey, value) values (?, ?)", (key,value)) | ||||
def add(self, fname, ftype=None, timestamp=None, content=None, version=None): | |||||
def add(self, fname, ftype=None, timestamp=None, content=None, version=None, action=None): | |||||
""" | """ | ||||
add to uncommitted | add to uncommitted | ||||
""" | """ | ||||
import os | import os | ||||
if not timestamp: | |||||
timestamp = self.vc.timestamp(fname) | |||||
# commit relative path | # commit relative path | ||||
fname = os.path.relpath(fname, self.vc.root_path) | |||||
fname = self.vc.relpath(fname) | |||||
if not action: | |||||
action = 'add' | |||||
if not ftype: | if not ftype: | ||||
ftype = fname.split('.')[-1] | ftype = fname.split('.')[-1] | ||||
if not timestamp: | |||||
timestamp = self.vc.timestamp(fname) | |||||
self.sql("insert or replace into uncommitted(fname, ftype, timestamp, content) values (?, ?, ?, ?)" \ | |||||
, (fname, ftype, timestamp, content)) | |||||
self.sql("insert or replace into uncommitted(fname, ftype, timestamp, content, action) values (?, ?, ?, ?, ?)" \ | |||||
, (fname, ftype, timestamp, content, action)) | |||||
def new_version(self): | def new_version(self): | ||||
""" | """ | ||||
@@ -340,29 +392,28 @@ class Repository: | |||||
added = self.sql("select * from uncommitted", as_dict=1) | added = self.sql("select * from uncommitted", as_dict=1) | ||||
for f in added: | for f in added: | ||||
if f['action']=='add': | |||||
# move them to "files" | |||||
self.sql(""" | |||||
insert or replace into files | |||||
(fname, ftype, timestamp, content, version) | |||||
values (?,?,?,?,?) | |||||
""", (f['fname'], f['ftype'], f['timestamp'], f['content'], version)) | |||||
elif f['action']=='remove': | |||||
self.sql("""delete from files where fname=?""", (f['fname'],)) | |||||
else: | |||||
raise Exception, 'bad action %s' % action | |||||
# move them to "files" | |||||
self.sql(""" | |||||
insert or replace into files | |||||
(fname, ftype, timestamp, content, version) | |||||
values (?,?,?,?,?) | |||||
""", (f['fname'], f['ftype'], f['timestamp'], f['content'], version)) | |||||
# update log | # update log | ||||
self.add_log(f['fname'], f['ftype'], version) | self.add_log(f['fname'], f['ftype'], version) | ||||
def exists(self, fname): | |||||
""" | |||||
true if exists | |||||
""" | |||||
fname = os.path.relpath(fname, self.vc.root_path) | |||||
return self.sql("select fname from files where fname=?", (fname,)) | |||||
def timestamp(self, fname): | def timestamp(self, fname): | ||||
""" | """ | ||||
get timestamp | get timestamp | ||||
""" | """ | ||||
fname = os.path.relpath(fname, self.vc.root_path) | |||||
fname = self.vc.relpath(fname) | |||||
return int(self.sql("select timestamp from files where fname=?", (fname,))[0][0] or 0) | return int(self.sql("select timestamp from files where fname=?", (fname,))[0][0] or 0) | ||||
def diff(self, number): | def diff(self, number): | ||||
@@ -383,12 +434,6 @@ class Repository: | |||||
""" | """ | ||||
return [f[0] for f in self.sql("select fname from uncommitted")] | return [f[0] for f in self.sql("select fname from uncommitted")] | ||||
def get_file(self, fname): | |||||
""" | |||||
return file info as dict | |||||
""" | |||||
return self.sql("select * from files where fname=?", (fname,), as_dict=1)[0] | |||||
def add_log(self, fname, ftype, version): | def add_log(self, fname, ftype, version): | ||||
""" | """ | ||||
add file to log | add file to log | ||||
@@ -44,10 +44,9 @@ def logout(): | |||||
# -------- | # -------- | ||||
def get_diff(): | def get_diff(): | ||||
import os | |||||
v = webnotes.form_dict.get('version_number') | v = webnotes.form_dict.get('version_number') | ||||
from build.version import VersionControl | from build.version import VersionControl | ||||
webnotes.response['message'] = VersionControl(os.path.abspath(os.path.curdir)).repo.diff(v) | |||||
webnotes.response['message'] = VersionControl().repo.diff(v) | |||||
# DocType Mapper | # DocType Mapper | ||||
# ------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------ | ||||
@@ -95,8 +95,14 @@ class Document: | |||||
def _loadfromdb(self, doctype = None, name = None): | def _loadfromdb(self, doctype = None, name = None): | ||||
if name: self.name = name | if name: self.name = name | ||||
if doctype: self.doctype = doctype | if doctype: self.doctype = doctype | ||||
if webnotes.model.meta.is_single(self.doctype): | |||||
is_single = False | |||||
try: | |||||
is_single = webnotes.model.meta.is_single(self.doctype) | |||||
except Exception, e: | |||||
pass | |||||
if is_single: | |||||
self._loadsingle() | self._loadsingle() | ||||
else: | else: | ||||
dataset = webnotes.conn.sql('select * from `%s%s` where name="%s"' % (self._prefix, self.doctype, self.name.replace('"', '\"'))) | dataset = webnotes.conn.sql('select * from `%s%s` where name="%s"' % (self._prefix, self.doctype, self.name.replace('"', '\"'))) | ||||
@@ -0,0 +1,171 @@ | |||||
""" | |||||
startup info for the app | |||||
client needs info that is static across all users | |||||
and user specific info like roles and defaults | |||||
so calling will be: | |||||
index.cgi?cmd=webnotes.startup.common_info | |||||
index.cgi?cmd=webnotes.startup.user_info&user=x@y.com | |||||
to clear startup, | |||||
you must clear all files in the vcs starting with index.cgi?cmd=webnotes.startup | |||||
""" | |||||
import webnotes | |||||
def get_letter_heads(): | |||||
""" | |||||
get letter head | |||||
""" | |||||
import webnotes | |||||
try: | |||||
lh = {} | |||||
ret = webnotes.conn.sql("select name, content from `tabLetter Head` where ifnull(disabled,0)=0") | |||||
for r in ret: | |||||
lh[r[0]] = r[1] | |||||
return lh | |||||
except Exception, e: | |||||
if e.args[0]==1146: | |||||
return {} | |||||
else: | |||||
raise Exception, e | |||||
def get_content_user(): | |||||
""" | |||||
get user specific content | |||||
""" | |||||
import webnotes | |||||
import webnotes.utils | |||||
import webnotes.widgets.page | |||||
import webnotes.widgets.menus | |||||
user = webnotes.form_dict['user'] | |||||
doclist, ret = [], {} | |||||
webnotes.conn.begin() | |||||
ret['profile'] = webnotes.user.load_profile() | |||||
home_page = webnotes.user.get_home_page() | |||||
if home_page: | |||||
doclist += webnotes.widgets.page.get(home_page) | |||||
ret['sysdefaults'] = webnotes.utils.get_defaults() | |||||
ret['home_page'] = home_page or '' | |||||
# role-wise menus | |||||
ret['start_items'] = webnotes.widgets.menus.get_menu_items() | |||||
# bundle | |||||
webnotes.session['data']['profile'] = ret['profile'] | |||||
if webnotes.session['data'].get('ipinfo'): | |||||
ret['ipinfo'] = webnotes.session['data']['ipinfo'] | |||||
webnotes.conn.commit() | |||||
webnotes.response['docs'] = doclist | |||||
return ret | |||||
def get_content_common(): | |||||
""" | |||||
build common startup info | |||||
""" | |||||
import webnotes | |||||
import webnotes.model.doc | |||||
import webnotes.model.doctype | |||||
import webnotes.model | |||||
doclist, ret = [], {} | |||||
doclist += webnotes.model.doc.get('Control Panel') | |||||
doclist += webnotes.model.doctype.get('Event') | |||||
doclist += webnotes.model.doctype.get('Search Criteria') | |||||
cp = doclist[0] | |||||
ret['account_name'] = cp.account_id or '' | |||||
ret['letter_heads'] = get_letter_heads() | |||||
ret['dt_labels'] = webnotes.model.get_dt_labels() | |||||
webnotes.response['docs'] = doclist | |||||
return ret | |||||
def common_info(): | |||||
""" | |||||
get common startup info (from version or live) | |||||
""" | |||||
get_info('index.cgi?cmd=webnotes.startup.common_info', 'common') | |||||
def user_info(): | |||||
""" | |||||
get user info | |||||
""" | |||||
user = webnotes.form_dict['user'] | |||||
get_info('index.cgi?cmd=webnotes.startup.user_info&user='+user, 'user') | |||||
def get_info(fname, key): | |||||
""" | |||||
get info from version or re-build | |||||
""" | |||||
from build.version import VersionControl | |||||
vc = VersionControl() | |||||
# from versions (same static) | |||||
if vc.exists(fname): | |||||
content = vc.get_file(fname)['content'] | |||||
else: | |||||
content = globals().get('get_content_'+key)() | |||||
import json | |||||
content = json.dumps(content) | |||||
# add in vcs | |||||
vc.add(fname=fname, content=content) | |||||
vc.commit() | |||||
vc.close() | |||||
webnotes.response['content'] = content | |||||
return | |||||
def clear_info(info_type=None): | |||||
""" | |||||
clear startup info and force a new version | |||||
parameter: info_type = 'user' or 'common' or 'all' | |||||
""" | |||||
if not info_type: | |||||
info_type = webnotes.form_dict.get('info_type') | |||||
from build.version import VersionControl | |||||
vc = VersionControl() | |||||
flist = [] | |||||
if info_type=='common': | |||||
flist = ['index.cgi?cmd=webnotes.startup.common_info'] | |||||
elif info_type=='user': | |||||
flist = [f[0] for f in vc.repo.sql("""select fname from files where fname like ?""",\ | |||||
('index.cgi?cmd=webnotes.startup.user_info%',))] | |||||
elif info_type=='all': | |||||
flist = [f[0] for f in vc.repo.sql("""select fname from files where fname like ?""",\ | |||||
('index.cgi?cmd=webnotes.startup%',))] | |||||
else: | |||||
webnotes.msgprint("info_type not found: %s" % info_type) | |||||
for f in flist: | |||||
print 'clearing %s' % f | |||||
vc.remove(f) | |||||
vc.commit() | |||||
vc.close() |
@@ -15,7 +15,7 @@ import sys, os | |||||
import unittest | import unittest | ||||
# webnotes path | # webnotes path | ||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) | |||||
sys.path.append('lib/py') | |||||
# modules path | # modules path | ||||
import webnotes | import webnotes | ||||
@@ -8,29 +8,149 @@ | |||||
# ------------------------------------------ | # ------------------------------------------ | ||||
import webnotes | |||||
import webnotes, unittest | |||||
class TestNSM(unittest.TestCase): | |||||
def setUp(self): | |||||
from webnotes.model.doc import Document | |||||
self.root = Document(fielddata={'doctype':'nsmtest', 'name':'T001', 'parent':None}) | |||||
self.first_child = Document(fielddata={'doctype':'nsmtest', 'name':'C001', 'parent_node':'T001'}) | |||||
self.first_sibling = Document(fielddata={'doctype':'nsmtest', 'name':'C002', 'parent_node':'T001'}) | |||||
self.grand_child = Document(fielddata={'doctype':'nsmtest', 'name':'GC001', 'parent_node':'C001'}) | |||||
webnotes.conn.sql(""" | |||||
create table `tabnsmtest` ( | |||||
name varchar(120) not null primary key, | |||||
creation datetime, | |||||
modified datetime, | |||||
modified_by varchar(40), | |||||
owner varchar(40), | |||||
docstatus int(1) default '0', | |||||
parent varchar(120), | |||||
parentfield varchar(120), | |||||
parenttype varchar(120), | |||||
idx int(8), | |||||
parent_node varchar(180), | |||||
old_parent varchar(180), | |||||
lft int, | |||||
rgt int) ENGINE=InnoDB""") | |||||
def test_root(self): | |||||
self.root.save(1) | |||||
update_nsm(self.root) | |||||
self.assertTrue(self.root.lft==1) | |||||
self.assertTrue(self.root.rgt==2) | |||||
def test_first_child(self): | |||||
self.root.save(1) | |||||
update_nsm(self.root) | |||||
self.first_child.save(1) | |||||
update_nsm(self.first_child) | |||||
self.root._loadfromdb() | |||||
self.assertTrue(self.root.lft==1) | |||||
self.assertTrue(self.first_child.lft==2) | |||||
self.assertTrue(self.first_child.rgt==3) | |||||
self.assertTrue(self.root.rgt==4) | |||||
def test_sibling(self): | |||||
self.test_first_child() | |||||
self.first_sibling.save(1) | |||||
update_nsm(self.first_sibling) | |||||
self.root._loadfromdb() | |||||
self.first_child._loadfromdb() | |||||
self.assertTrue(self.root.lft==1) | |||||
self.assertTrue(self.first_child.lft==2) | |||||
self.assertTrue(self.first_child.rgt==3) | |||||
self.assertTrue(self.first_sibling.lft==4) | |||||
self.assertTrue(self.first_sibling.rgt==5) | |||||
self.assertTrue(self.root.rgt==6) | |||||
def test_remove_sibling(self): | |||||
self.test_sibling() | |||||
self.first_sibling.parent_node = '' | |||||
update_nsm(self.first_sibling) | |||||
self.root._loadfromdb() | |||||
self.first_child._loadfromdb() | |||||
self.assertTrue(self.root.lft==1) | |||||
self.assertTrue(self.first_child.lft==2) | |||||
self.assertTrue(self.first_child.rgt==3) | |||||
self.assertTrue(self.root.rgt==4) | |||||
self.assertTrue(self.first_sibling.lft==5) | |||||
self.assertTrue(self.first_sibling.rgt==6) | |||||
def test_change_parent(self): | |||||
self.test_sibling() | |||||
# add grand child | |||||
self.grand_child.save(1) | |||||
update_nsm(self.grand_child) | |||||
# check lft rgt | |||||
self.assertTrue(self.grand_child.lft==3) | |||||
self.assertTrue(self.grand_child.rgt==4) | |||||
# change parent | |||||
self.grand_child.parent_node = 'C002' | |||||
self.grand_child.save() | |||||
# update | |||||
update_nsm(self.grand_child) | |||||
# check lft rgt | |||||
self.assertTrue(self.grand_child.lft==5) | |||||
self.assertTrue(self.grand_child.rgt==6) | |||||
def tearDown(self): | |||||
webnotes.conn.sql("drop table tabnsmtest") | |||||
# called in the on_update method | # called in the on_update method | ||||
def update_nsm(doc_obj): | def update_nsm(doc_obj): | ||||
# get fields, data from the DocType | # get fields, data from the DocType | ||||
d = doc_obj.doc | |||||
pf, opf = 'parent_node', 'old_parent' | pf, opf = 'parent_node', 'old_parent' | ||||
if hasattr(doc_obj,'nsm_parent_field'): | |||||
pf = doc_obj.nsm_parent_field | |||||
if hasattr(doc_obj,'nsm_oldparent_field'): | |||||
opf = doc_obj.nsm_oldparent_field | |||||
p, op = d.fields[pf], d.fields.get(opf, '') | |||||
if str(doc_obj.__class__)=='webnotes.model.doc.Document': | |||||
# passed as a Document object | |||||
d = doc_obj | |||||
else: | |||||
# passed as a DocType object | |||||
d = doc_obj.doc | |||||
if hasattr(doc_obj,'nsm_parent_field'): | |||||
pf = doc_obj.nsm_parent_field | |||||
if hasattr(doc_obj,'nsm_oldparent_field'): | |||||
opf = doc_obj.nsm_oldparent_field | |||||
p, op = d.fields.get(pf, ''), d.fields.get(opf, '') | |||||
# has parent changed (?) or parent is None (root) | # has parent changed (?) or parent is None (root) | ||||
if not doc_obj.doc.lft and not doc_obj.doc.rgt: | |||||
update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf) | |||||
if not d.lft and not d.rgt: | |||||
update_add_node(d.doctype, d.name, p or '', pf) | |||||
elif op != p: | elif op != p: | ||||
update_remove_node(doc_obj.doc.doctype, doc_obj.doc.name) | |||||
update_add_node(doc_obj.doc.doctype, doc_obj.doc.name, p or '', pf) | |||||
update_remove_node(d.doctype, d.name) | |||||
update_add_node(d.doctype, d.name, p or '', pf) | |||||
# set old parent | # set old parent | ||||
webnotes.conn.set(d, opf, p or '') | webnotes.conn.set(d, opf, p or '') | ||||
# reload | |||||
d._loadfromdb() | |||||
def rebuild_tree(doctype, parent_field): | def rebuild_tree(doctype, parent_field): | ||||
""" | |||||
call rebuild_node for all root nodes | |||||
""" | |||||
# get all roots | # get all roots | ||||
right = 1 | right = 1 | ||||
result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='' or `%s` IS NULL" % (doctype, parent_field, parent_field)) | result = webnotes.conn.sql("SELECT name FROM `tab%s` WHERE `%s`='' or `%s` IS NULL" % (doctype, parent_field, parent_field)) | ||||
@@ -38,6 +158,12 @@ def rebuild_tree(doctype, parent_field): | |||||
right = rebuild_node(doctype, r[0], right, parent_field) | right = rebuild_node(doctype, r[0], right, parent_field) | ||||
def rebuild_node(doctype, parent, left, parent_field): | def rebuild_node(doctype, parent, left, parent_field): | ||||
""" | |||||
reset lft, rgt and recursive call for all children | |||||
""" | |||||
from webnotes.utils import now | |||||
n = now() | |||||
# the right value of this node is the left value + 1 | # the right value of this node is the left value + 1 | ||||
right = left+1 | right = left+1 | ||||
@@ -48,37 +174,50 @@ def rebuild_node(doctype, parent, left, parent_field): | |||||
# we've got the left value, and now that we've processed | # we've got the left value, and now that we've processed | ||||
# the children of this node we also know the right value | # the children of this node we also know the right value | ||||
webnotes.conn.sql('UPDATE `tab%s` SET lft=%s, rgt=%s WHERE name="%s"' % (doctype,left,right,parent)) | |||||
webnotes.conn.sql("UPDATE `tab%s` SET lft=%s, rgt=%s, modified='%s' WHERE name='%s'" % (doctype,left,right,n,parent)) | |||||
#return the right value of this node + 1 | #return the right value of this node + 1 | ||||
return right+1 | return right+1 | ||||
def update_add_node(doctype, name, parent, parent_field): | def update_add_node(doctype, name, parent, parent_field): | ||||
""" | |||||
insert a new node | |||||
""" | |||||
from webnotes.utils import now | |||||
n = now() | |||||
# get the last sibling of the parent | # get the last sibling of the parent | ||||
if parent: | if parent: | ||||
right = webnotes.conn.sql("select rgt from `tab%s` where name='%s'" % (doctype, parent))[0][0] | right = webnotes.conn.sql("select rgt from `tab%s` where name='%s'" % (doctype, parent))[0][0] | ||||
else: # root | else: # root | ||||
right = webnotes.conn.sql("select ifnull(max(rgt),0)+1 from `tab%s` where ifnull(`%s`,'') =''" % (doctype, parent_field))[0][0] | right = webnotes.conn.sql("select ifnull(max(rgt),0)+1 from `tab%s` where ifnull(`%s`,'') =''" % (doctype, parent_field))[0][0] | ||||
right = right or 1 | right = right or 1 | ||||
# update all on the right | # update all on the right | ||||
webnotes.conn.sql("update `tab%s` set rgt = rgt+2 where rgt >= %s" %(doctype,right)) | |||||
webnotes.conn.sql("update `tab%s` set lft = lft+2 where lft >= %s" %(doctype,right)) | |||||
webnotes.conn.sql("update `tab%s` set rgt = rgt+2, modified='%s' where rgt >= %s" %(doctype,n,right)) | |||||
webnotes.conn.sql("update `tab%s` set lft = lft+2, modified='%s' where lft >= %s" %(doctype,n,right)) | |||||
# update index of new node | # update index of new node | ||||
if webnotes.conn.sql("select * from `tab%s` where lft=%s or rgt=%s"% (doctype, right, right+1)): | if webnotes.conn.sql("select * from `tab%s` where lft=%s or rgt=%s"% (doctype, right, right+1)): | ||||
webnotes.msgprint("Nested set error. Please send mail to support") | webnotes.msgprint("Nested set error. Please send mail to support") | ||||
raise Exception | raise Exception | ||||
webnotes.conn.sql("update `tab%s` set lft=%s, rgt=%s where name='%s'" % (doctype,right,right+1,name)) | |||||
webnotes.conn.sql("update `tab%s` set lft=%s, rgt=%s, modified='%s' where name='%s'" % (doctype,right,right+1,n,name)) | |||||
return right | return right | ||||
def update_remove_node(doctype, name): | def update_remove_node(doctype, name): | ||||
""" | |||||
remove a node | |||||
""" | |||||
from webnotes.utils import now | |||||
n = now() | |||||
left = webnotes.conn.sql("select lft from `tab%s` where name='%s'" % (doctype,name)) | left = webnotes.conn.sql("select lft from `tab%s` where name='%s'" % (doctype,name)) | ||||
if left[0][0]: | if left[0][0]: | ||||
# reset this node | # reset this node | ||||
webnotes.conn.sql("update `tab%s` set lft=0, rgt=0 where name='%s'" % (doctype,name)) | |||||
webnotes.conn.sql("update `tab%s` set lft=0, rgt=0, modified='%s' where name='%s'" % (doctype,n,name)) | |||||
# update all on the right | # update all on the right | ||||
webnotes.conn.sql("update `tab%s` set rgt = rgt-2 where rgt > %s" %(doctype,left[0][0])) | |||||
webnotes.conn.sql("update `tab%s` set lft = lft-2 where lft > %s" %(doctype,left[0][0])) | |||||
webnotes.conn.sql("update `tab%s` set rgt = rgt-2, modified='%s' where rgt > %s" %(doctype,n,left[0][0])) | |||||
webnotes.conn.sql("update `tab%s` set lft = lft-2, modified='%s' where lft > %s" %(doctype,n,left[0][0])) | |||||
@@ -9,7 +9,6 @@ version.verbose = True | |||||
def run(): | def run(): | ||||
sys.path.append('lib') | sys.path.append('lib') | ||||
sys.path.append('lib/py') | sys.path.append('lib/py') | ||||
vc = version.VersionControl(os.path.abspath(os.curdir)) | |||||
if len(sys.argv)<2: | if len(sys.argv)<2: | ||||
print "wnframework version control utility" | print "wnframework version control utility" | ||||
@@ -20,25 +19,13 @@ def run(): | |||||
if cmd=='build': | if cmd=='build': | ||||
from py import build | from py import build | ||||
build.run(os.path.abspath(os.curdir)) | |||||
if cmd=='add': | |||||
if not len(sys.argv)>1: | |||||
print 'usage: wnf add path/to/file' | |||||
return | |||||
vc.repo.add(sys.argv[2]) | |||||
if cmd=='commit': | |||||
if len(sys.argv>2) and sys.argv[2]=='-a': | |||||
vc.add_all() | |||||
vc.repo.commit() | |||||
if cmd=='diff': | |||||
vc.repo.uncommitted() | |||||
build.run() | |||||
vc = version.VersionControl() | |||||
print 'version %s' % vc.repo.get_value('last_version_number') | |||||
if cmd=='merge': | if cmd=='merge': | ||||
vc = version.VersionControl() | |||||
vc.setup_master() | vc.setup_master() | ||||
if sys.argv[2]=='local': | if sys.argv[2]=='local': | ||||
vc.merge(vc.repo, vc.master) | vc.merge(vc.repo, vc.master) | ||||
@@ -47,11 +34,32 @@ def run(): | |||||
else: | else: | ||||
print "usage: wnf merge local|master" | print "usage: wnf merge local|master" | ||||
print "help: parameter (local or master) is the source" | print "help: parameter (local or master) is the source" | ||||
vc.close() | |||||
if cmd=='setup': | if cmd=='setup': | ||||
vc = version.VersionControl() | |||||
vc.repo.setup() | vc.repo.setup() | ||||
vc.close() | |||||
if cmd=='clear_startup': | |||||
from webnotes import startup | |||||
startup.clear_info('all') | |||||
vc.close() | |||||
vc = version.VersionControl() | |||||
print 'version %s' % vc.repo.get_value('last_version_number') | |||||
if cmd=='log': | |||||
vc = version.VersionControl() | |||||
for l in vc.repo.sql("select * from log order by rowid desc limit 10 ", as_dict =1): | |||||
print 'file:'+ l['fname'] + ' | version: ' + l['version'] | |||||
print 'version %s' % vc.repo.get_value('last_version_number') | |||||
vc.close() | |||||
if cmd=='files': | |||||
vc = version.VersionControl() | |||||
for f in vc.repo.sql("select fname from files where fname like ?", ((sys.argv[2] + '%'),)): | |||||
print f[0] | |||||
vc.close() | |||||
if __name__=='__main__': | if __name__=='__main__': | ||||
run() | run() |