Shortcut for commiting log items

This commit is contained in:
Dmitry Shulyak 2015-05-29 12:19:58 +02:00
parent 3b56aab142
commit 36e3b240f9
6 changed files with 115 additions and 23 deletions

4
.gitignore vendored
View File

@ -10,3 +10,7 @@ tmp/
#vim #vim
*.swp *.swp
state/
clients.json
rs/

24
cli.py
View File

@ -11,6 +11,7 @@ import subprocess
from solar.core import actions as xa from solar.core import actions as xa
from solar.core import resource as xr from solar.core import resource as xr
from solar.core import signals as xs from solar.core import signals as xs
from solar import operations
@click.group() @click.group()
@ -137,6 +138,28 @@ def init_cli_connect():
cli.add_command(disconnect) cli.add_command(disconnect)
def init_changes():
@click.group()
def changes():
pass
cli.add_command(changes)
@click.command()
@click.argument('path')
def stage(path):
log = operations.stage_changes(path)
print log.show()
changes.add_command(stage)
@click.command()
def commit():
operations.commit_changes()
changes.add_command(commit)
def init_cli_connections(): def init_cli_connections():
@click.group() @click.group()
def connections(): def connections():
@ -185,5 +208,6 @@ if __name__ == '__main__':
init_cli_connect() init_cli_connect()
init_cli_connections() init_cli_connections()
init_cli_deployment_config() init_cli_deployment_config()
init_changes()
cli() cli()

View File

@ -5,3 +5,5 @@ PyYAML==3.11
jsonschema==2.4.0 jsonschema==2.4.0
requests==2.7.0 requests==2.7.0
mock mock
dictdiffer==0.4.0
enum34==1.0.4

View File

@ -4,6 +4,7 @@ import os
from copy import deepcopy from copy import deepcopy
<<<<<<< HEAD
import yaml import yaml
import solar import solar
@ -118,6 +119,8 @@ class Resource(object):
metadata['input'][k]['value'] = v metadata['input'][k]['value'] = v
db.add_resource(self.name, metadata) db.add_resource(self.name, metadata)
meta_file = os.path.join(self.base_dir, 'meta.yaml')
utils.yaml_dump_to(metadata, meta_file)
def create(name, base_path, args, tags=[], connections={}): def create(name, base_path, args, tags=[], connections={}):
@ -127,7 +130,7 @@ def create(name, base_path, args, tags=[], connections={}):
base_meta_file = os.path.join(base_path, 'meta.yaml') base_meta_file = os.path.join(base_path, 'meta.yaml')
actions_path = os.path.join(base_path, 'actions') actions_path = os.path.join(base_path, 'actions')
meta = yaml.load(open(base_meta_file).read()) meta = utils.yaml_load(base_meta_file)
meta['id'] = name meta['id'] = name
meta['version'] = '1.0.0' meta['version'] = '1.0.0'
meta['actions'] = {} meta['actions'] = {}

View File

@ -3,33 +3,38 @@
from solar import state from solar import state
from solar.core import signals from solar.core import signals
from solar.core import resource from solar.core import resource
from solar import utils
from dictdiffer import diff from dictdiffer import diff, patch
import networkx as nx import networkx as nx
def connections(res, graph): def connections(res, graph):
result = []
for pred in graph.predecessors(res.name): for pred in graph.predecessors(res.name):
edge = graph.get_edge_edge(pred, res.name) edge = graph.get_edge_data(pred, res.name)
if ':' in edge['label']: if 'label' in edge:
parent, child = edge['label'].split(':') if ':' in edge['label']:
yield pred, res.name, {parent: child} parent, child = edge['label'].split(':')
mapping = {parent: child}
else:
mapping = {edge['label']: edge['label']}
else: else:
yield pred, res.name, {edge['label']: edge['label']} mapping = None
result.append((pred, res.name, mapping))
return result
def to_dict(resource, graph): def to_dict(resource, graph):
return {'uid': resource.name, return {'uid': resource.name,
'path': resource.dest_path, 'path': resource.base_dir,
'meta': resource.metadata,
'tags': resource.tags, 'tags': resource.tags,
'args': resource.args_dict(), 'args': resource.args_dict(),
'connections': connections(resource, graph)} 'connections': connections(resource, graph)}
def stage_changes(): def stage_changes(path):
resources = resource.load_all() resources = resource.load_all(path)
conn_graph = signals.detailed_connection_graph() conn_graph = signals.detailed_connection_graph()
commited = state.CD() commited = state.CD()
@ -38,7 +43,7 @@ def stage_changes():
for res_uid in nx.topological_sort(conn_graph): for res_uid in nx.topological_sort(conn_graph):
commited_data = commited.get(res_uid, {}) commited_data = commited.get(res_uid, {})
staged_data = to_dict(resources[res_uid], conn_graph) staged_data = to_dict(resources[res_uid], conn_graph)
df = diff(commited_data, staged_data) df = list(diff(commited_data, staged_data))
if df: if df:
log_item = state.LogItem( log_item = state.LogItem(
@ -48,3 +53,15 @@ def stage_changes():
log.add(log_item) log.add(log_item)
return log return log
def commit_changes():
# just shortcut to test stuff
commited = state.CD()
history = state.CL()
staged = state.SL()
while staged.items:
l = staged.popleft()
commited[l.res] = patch(commited.get(l.res, {}), l.diff)
l.state = state.states.success
history.add(l)

View File

@ -12,24 +12,50 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import os
import collections import collections
from collections import deque from collections import deque
from functools import partial
from solar import utils
from enum import Enum
states = Enum('States', 'pending inprogress error success')
def state_file(filename):
filepath = os.path.join(utils.read_config()['state'], filename)
if 'log' in filename:
return Log(filepath)
elif 'data' in filename:
return Data(filepath)
CD = partial(state_file, 'commited_data')
SD = partial(state_file, 'staged_data')
SL = partial(state_file, 'stage_log')
IL = partial(state_file, 'inprogress_log')
CL = partial(state_file, 'commit_log')
class LogItem(object): class LogItem(object):
def __init__(self, uid, res_uid, diff): def __init__(self, uid, res_uid, diff, state=None):
self.uid = uid self.uid = uid
self.res = res_uid self.res = res_uid
self.diff = diff self.diff = diff
self.state = state or states.pending
def to_yaml(self): def to_yaml(self):
return utils.yaml_dump(self.to_dict()) return utils.yaml_dump(self.to_dict())
def to_dict(self): def to_dict(self):
return {'uid': self.uid, return {'uid': self.uid,
'res': self.res_uid, 'res': self.res,
'diff': self.diff} 'diff': self.diff,
'state': self.state.name}
def __str__(self): def __str__(self):
return self.to_yaml() return self.to_yaml()
@ -42,18 +68,27 @@ class Log(object):
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
self.items = deque([LogItem(**l) for items = utils.yaml_load(path) or []
l in utils.yaml_load(path)]) self.items = deque([LogItem(
l['uid'], l['res'],
l['diff'], getattr(states, l['state'])) for l in items])
def sync(self):
utils.yaml_dump_to([i.to_dict() for i in self.items], self.path)
def add(self, logitem): def add(self, logitem):
self.items.append(logitem) self.items.append(logitem)
utils.yaml_dump_to(self.items, path) self.sync()
def popleft(self): def popleft(self):
item = self.items.popleft() item = self.items.popleft()
utils.yaml_dump_to(self.items, path) self.sync()
return item return item
def show(self, verbose=False):
return ['L(uuid={0}, res={1})'.format(l.uid, l.res)
for l in self.items]
def __repr__(self): def __repr__(self):
return 'Log({0})'.format(self.path) return 'Log({0})'.format(self.path)
@ -62,15 +97,22 @@ class Data(collections.MutableMapping):
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
self.store = utils.yaml_load(path) self.store = utils.yaml_load(path) or {}
def __getitem__(self, key): def __getitem__(self, key):
return self.store[key] return self.store[key]
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.store[key] = value self.store[key] = value
utils.yaml_dump_to(self.store, path) utils.yaml_dump_to(self.store, self.path)
def __delitem__(self, key): def __delitem__(self, key):
self.store.pop(key) self.store.pop(key)
utils.yaml_dump_to(self.store, path) utils.yaml_dump_to(self.store, self.path)
def __iter__(self):
return iter(self.store)
def __len__(self):
return len(self.store)