Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2013-07-07 06:02:19 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2013-07-07 06:02:19 (GMT)
commit35d777deda94fbc78324c447e16bb7abf0b11434 (patch)
tree241259c32a05c297de62e4d84d17a638d3bc4fe4
parent0f9ae89f82a872f7449b8e2d72b7d6f63fa0180d (diff)
Reuse node clone API command for cloning implementation from client app; process requires clone argument properly
-rw-r--r--doc/objects.dia1503
-rw-r--r--sugar_network/client/cache.py4
-rw-r--r--sugar_network/client/clones.py2
-rw-r--r--sugar_network/client/commands.py2
-rw-r--r--sugar_network/client/injector.py17
-rw-r--r--sugar_network/client/solver.py3
-rw-r--r--sugar_network/db/router.py30
-rw-r--r--sugar_network/node/commands.py78
-rw-r--r--sugar_network/resources/context.py5
-rw-r--r--sugar_network/resources/implementation.py88
-rw-r--r--sugar_network/toolkit/http.py52
-rw-r--r--sugar_network/toolkit/spec.py136
-rw-r--r--sugar_network/toolkit/util.py33
-rw-r--r--tests/__init__.py8
-rwxr-xr-xtests/units/client/injector.py159
-rwxr-xr-xtests/units/client/online_commands.py229
-rwxr-xr-xtests/units/node/node.py122
-rwxr-xr-xtests/units/node/volume.py1
-rwxr-xr-xtests/units/resources/implementation.py106
-rwxr-xr-xtests/units/toolkit/spec.py49
20 files changed, 1453 insertions, 1174 deletions
diff --git a/doc/objects.dia b/doc/objects.dia
index 3e75873..9444a06 100644
--- a/doc/objects.dia
+++ b/doc/objects.dia
@@ -2,10 +2,10 @@
<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
<dia:diagramdata>
<dia:attribute name="background">
- <dia:color val="#ffffff"/>
+ <dia:color val="#ffffffff"/>
</dia:attribute>
<dia:attribute name="pagebreak">
- <dia:color val="#000099"/>
+ <dia:color val="#000099ff"/>
</dia:attribute>
<dia:attribute name="paper">
<dia:composite type="paper">
@@ -37,6 +37,9 @@
</dia:attribute>
<dia:attribute name="grid">
<dia:composite type="grid">
+ <dia:attribute name="dynamic">
+ <dia:boolean val="true"/>
+ </dia:attribute>
<dia:attribute name="width_x">
<dia:real val="0.40000000000000002"/>
</dia:attribute>
@@ -53,7 +56,7 @@
</dia:composite>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#d8e5e5"/>
+ <dia:color val="#d8e5e5ff"/>
</dia:attribute>
<dia:attribute name="guides">
<dia:composite type="guides">
@@ -61,6 +64,25 @@
<dia:attribute name="vguides"/>
</dia:composite>
</dia:attribute>
+ <dia:attribute name="display">
+ <dia:composite type="display">
+ <dia:attribute name="antialiased">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="snap-to-grid">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="snap-to-object">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="show-grid">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="show-connection-points">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
</dia:diagramdata>
<dia:layer name="Background" visible="true" active="true">
<dia:object type="UML - Class" version="0" id="O0">
@@ -68,7 +90,7 @@
<dia:point val="30,8"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="29.985,7.985;48.6675,44.415"/>
+ <dia:rectangle val="29.985,7.985;48.6675,42.415"/>
</dia:attribute>
<dia:attribute name="elem_corner">
<dia:point val="30,8"/>
@@ -77,7 +99,7 @@
<dia:real val="18.6525"/>
</dia:attribute>
<dia:attribute name="elem_height">
- <dia:real val="36.400000000000006"/>
+ <dia:real val="34.400000000000006"/>
</dia:attribute>
<dia:attribute name="name">
<dia:string>#Context#</dia:string>
@@ -118,17 +140,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#c1cccc"/>
+ <dia:color val="#c1ccccff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -192,29 +217,6 @@
</dia:composite>
<dia:composite type="umlattribute">
<dia:attribute name="name">
- <dia:string>#implement#</dia:string>
- </dia:attribute>
- <dia:attribute name="type">
- <dia:string>#[str] [R WA]#</dia:string>
- </dia:attribute>
- <dia:attribute name="value">
- <dia:string>#[]#</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#Sugar Network names that this Content associated with#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="class_scope">
- <dia:boolean val="false"/>
- </dia:attribute>
- </dia:composite>
- <dia:composite type="umlattribute">
- <dia:attribute name="name">
<dia:string>#title#</dia:string>
</dia:attribute>
<dia:attribute name="type">
@@ -533,7 +535,7 @@
<dia:real val="11.532500000000001"/>
</dia:attribute>
<dia:attribute name="elem_height">
- <dia:real val="27.600000000000005"/>
+ <dia:real val="27.600000000000001"/>
</dia:attribute>
<dia:attribute name="name">
<dia:string>#User#</dia:string>
@@ -574,17 +576,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#90ee90"/>
+ <dia:color val="#90ee90ff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -848,7 +853,7 @@
<dia:point val="12,6"/>
</dia:attribute>
<dia:attribute name="elem_width">
- <dia:real val="11.755000000000001"/>
+ <dia:real val="11.754999999999999"/>
</dia:attribute>
<dia:attribute name="elem_height">
<dia:real val="20"/>
@@ -892,17 +897,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#ffffff"/>
+ <dia:color val="#ffffffff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -1087,6 +1095,29 @@
<dia:attribute name="templates"/>
</dia:object>
<dia:object type="UML - Association" version="2" id="O3">
+ <dia:attribute name="obj_pos">
+ <dia:point val="48.6525,33.1"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="48.6025,32.34;54.05,68.74"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="orth_points">
+ <dia:point val="48.6525,33.1"/>
+ <dia:point val="51,33.1"/>
+ <dia:point val="51,67.9"/>
+ <dia:point val="54,67.9"/>
+ </dia:attribute>
+ <dia:attribute name="orth_orient">
+ <dia:enum val="0"/>
+ <dia:enum val="1"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="orth_autoroute">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -1123,20 +1154,41 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O0" connection="29"/>
+ <dia:connection handle="1" to="O14" connection="12"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O4">
<dia:attribute name="obj_pos">
- <dia:point val="48.6525,35.1"/>
+ <dia:point val="54,69.9"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="48.6025,34.3;54.05,68.7"/>
+ <dia:rectangle val="46.95,67.9293;54.05,70.74"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="orth_points">
- <dia:point val="48.6525,35.1"/>
- <dia:point val="51,35.1"/>
- <dia:point val="51,67.9"/>
- <dia:point val="54,67.9"/>
+ <dia:point val="54,69.9"/>
+ <dia:point val="47,69.9"/>
+ <dia:point val="47,68"/>
+ <dia:point val="47,68"/>
</dia:attribute>
<dia:attribute name="orth_orient">
<dia:enum val="0"/>
@@ -1146,18 +1198,6 @@
<dia:attribute name="orth_autoroute">
<dia:boolean val="false"/>
</dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O0" connection="31"/>
- <dia:connection handle="1" to="O14" connection="12"/>
- </dia:connections>
- </dia:object>
- <dia:object type="UML - Association" version="2" id="O4">
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -1194,20 +1234,41 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O14" connection="14"/>
+ <dia:connection handle="1" to="O11" connection="4"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O5">
<dia:attribute name="obj_pos">
- <dia:point val="54,69.9"/>
+ <dia:point val="39.3263,42.4"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="46.95,67.9293;54.05,70.7"/>
+ <dia:rectangle val="39.2763,41.64;40.1,49.84"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="orth_points">
- <dia:point val="54,69.9"/>
- <dia:point val="47,69.9"/>
- <dia:point val="47,68"/>
- <dia:point val="47,68"/>
+ <dia:point val="39.3263,42.4"/>
+ <dia:point val="40,42.4"/>
+ <dia:point val="40,49"/>
+ <dia:point val="39.5,49"/>
</dia:attribute>
<dia:attribute name="orth_orient">
<dia:enum val="0"/>
@@ -1217,18 +1278,6 @@
<dia:attribute name="orth_autoroute">
<dia:boolean val="false"/>
</dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O14" connection="14"/>
- <dia:connection handle="1" to="O11" connection="4"/>
- </dia:connections>
- </dia:object>
- <dia:object type="UML - Association" version="2" id="O5">
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -1265,20 +1314,41 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O0" connection="6"/>
+ <dia:connection handle="1" to="O11" connection="1"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O6">
<dia:attribute name="obj_pos">
- <dia:point val="39.3263,44.4"/>
+ <dia:point val="30,33.1"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="39.2763,43.6;40.1,49.8"/>
+ <dia:rectangle val="26.385,32.34;30.05,73.14"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="orth_points">
- <dia:point val="39.3263,44.4"/>
- <dia:point val="40,44.4"/>
- <dia:point val="40,49"/>
- <dia:point val="39.5,49"/>
+ <dia:point val="30,33.1"/>
+ <dia:point val="28.2175,33.1"/>
+ <dia:point val="28.2175,72.3"/>
+ <dia:point val="26.435,72.3"/>
</dia:attribute>
<dia:attribute name="orth_orient">
<dia:enum val="0"/>
@@ -1286,20 +1356,8 @@
<dia:enum val="0"/>
</dia:attribute>
<dia:attribute name="orth_autoroute">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
+ <dia:boolean val="true"/>
</dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O0" connection="6"/>
- <dia:connection handle="1" to="O11" connection="1"/>
- </dia:connections>
- </dia:object>
- <dia:object type="UML - Association" version="2" id="O6">
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -1336,20 +1394,41 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O0" connection="28"/>
+ <dia:connection handle="1" to="O8" connection="11"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O7">
<dia:attribute name="obj_pos">
- <dia:point val="30,35.1"/>
+ <dia:point val="26.435,75.1"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="26.385,34.3;30.05,73.1"/>
+ <dia:rectangle val="26.385,67.24;32.0516,75.94"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="orth_points">
- <dia:point val="30,35.1"/>
- <dia:point val="28.2175,35.1"/>
- <dia:point val="28.2175,72.3"/>
- <dia:point val="26.435,72.3"/>
+ <dia:point val="26.435,75.1"/>
+ <dia:point val="30,75.1"/>
+ <dia:point val="30,68"/>
+ <dia:point val="32.0016,68"/>
</dia:attribute>
<dia:attribute name="orth_orient">
<dia:enum val="0"/>
@@ -1357,20 +1436,8 @@
<dia:enum val="0"/>
</dia:attribute>
<dia:attribute name="orth_autoroute">
- <dia:boolean val="true"/>
- </dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
+ <dia:boolean val="false"/>
</dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O0" connection="30"/>
- <dia:connection handle="1" to="O8" connection="11"/>
- </dia:connections>
- </dia:object>
- <dia:object type="UML - Association" version="2" id="O7">
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -1407,34 +1474,20 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
- <dia:attribute name="obj_pos">
- <dia:point val="26.435,75.1"/>
- </dia:attribute>
- <dia:attribute name="obj_bb">
- <dia:rectangle val="26.385,67.2;32,75.9"/>
- </dia:attribute>
- <dia:attribute name="meta">
- <dia:composite type="dict"/>
- </dia:attribute>
- <dia:attribute name="orth_points">
- <dia:point val="26.435,75.1"/>
- <dia:point val="30,75.1"/>
- <dia:point val="30,68"/>
- <dia:point val="31.95,68"/>
- </dia:attribute>
- <dia:attribute name="orth_orient">
- <dia:enum val="0"/>
- <dia:enum val="1"/>
- <dia:enum val="0"/>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
</dia:attribute>
- <dia:attribute name="orth_autoroute">
- <dia:boolean val="false"/>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
</dia:attribute>
<dia:attribute name="text_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
</dia:attribute>
<dia:attribute name="line_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:connections>
<dia:connection handle="0" to="O8" connection="13"/>
@@ -1452,10 +1505,10 @@
<dia:point val="14,66"/>
</dia:attribute>
<dia:attribute name="elem_width">
- <dia:real val="12.435"/>
+ <dia:real val="12.434999999999999"/>
</dia:attribute>
<dia:attribute name="elem_height">
- <dia:real val="14.799999999999999"/>
+ <dia:real val="14.800000000000001"/>
</dia:attribute>
<dia:attribute name="name">
<dia:string>#Feedback#</dia:string>
@@ -1496,17 +1549,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#d9e6e6"/>
+ <dia:color val="#d9e6e6ff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -1722,17 +1778,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#d8e5e5"/>
+ <dia:color val="#d8e5e5ff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -1848,6 +1907,29 @@
<dia:attribute name="templates"/>
</dia:object>
<dia:object type="UML - Association" version="2" id="O10">
+ <dia:attribute name="obj_pos">
+ <dia:point val="14,72.3"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="9.6625,72.25;14.2,76.1"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="orth_points">
+ <dia:point val="14,72.3"/>
+ <dia:point val="14,75"/>
+ <dia:point val="9.7125,75"/>
+ <dia:point val="9.7125,74.5"/>
+ </dia:attribute>
+ <dia:attribute name="orth_orient">
+ <dia:enum val="1"/>
+ <dia:enum val="0"/>
+ <dia:enum val="1"/>
+ </dia:attribute>
+ <dia:attribute name="orth_autoroute">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -1884,34 +1966,20 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
- <dia:attribute name="obj_pos">
- <dia:point val="14,72.3"/>
- </dia:attribute>
- <dia:attribute name="obj_bb">
- <dia:rectangle val="9.6625,72.25;14.2,76.1"/>
- </dia:attribute>
- <dia:attribute name="meta">
- <dia:composite type="dict"/>
- </dia:attribute>
- <dia:attribute name="orth_points">
- <dia:point val="14,72.3"/>
- <dia:point val="14,75"/>
- <dia:point val="9.7125,75"/>
- <dia:point val="9.7125,74.5"/>
- </dia:attribute>
- <dia:attribute name="orth_orient">
- <dia:enum val="1"/>
- <dia:enum val="0"/>
- <dia:enum val="1"/>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
</dia:attribute>
- <dia:attribute name="orth_autoroute">
- <dia:boolean val="false"/>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
</dia:attribute>
<dia:attribute name="text_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
</dia:attribute>
<dia:attribute name="line_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:connections>
<dia:connection handle="0" to="O8" connection="10"/>
@@ -1937,23 +2005,29 @@
<dia:attribute name="elem_height">
<dia:real val="38"/>
</dia:attribute>
- <dia:attribute name="line_width">
- <dia:real val="0.035277776420116425"/>
+ <dia:attribute name="name">
+ <dia:string>#Common objects #</dia:string>
</dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
+ <dia:attribute name="stereotype">
+ <dia:string>##</dia:string>
</dia:attribute>
- <dia:attribute name="fill_colour">
- <dia:color val="#f3f3f3"/>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
</dia:attribute>
<dia:attribute name="text_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
- <dia:attribute name="stereotype">
- <dia:string>##</dia:string>
+ <dia:attribute name="line_width">
+ <dia:real val="0.035277776420116425"/>
</dia:attribute>
- <dia:attribute name="name">
- <dia:string>#Common objects #</dia:string>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#f3f3f3ff"/>
</dia:attribute>
</dia:object>
<dia:object type="UML - Class" version="0" id="O12">
@@ -1961,16 +2035,16 @@
<dia:point val="33,69"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="32.985,68.985;45.63,85.415"/>
+ <dia:rectangle val="32.985,68.985;45.645,85.415"/>
</dia:attribute>
<dia:attribute name="elem_corner">
<dia:point val="33,69"/>
</dia:attribute>
<dia:attribute name="elem_width">
- <dia:real val="12.615"/>
+ <dia:real val="12.629999999999999"/>
</dia:attribute>
<dia:attribute name="elem_height">
- <dia:real val="16.399999999999999"/>
+ <dia:real val="16.400000000000002"/>
</dia:attribute>
<dia:attribute name="name">
<dia:string>#Comment#</dia:string>
@@ -2011,17 +2085,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#f1ffff"/>
+ <dia:color val="#f1ffffff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -2237,17 +2314,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#f1ffff"/>
+ <dia:color val="#f1ffffff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -2463,17 +2543,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#d8e5e5"/>
+ <dia:color val="#d8e5e5ff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -2827,17 +2910,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#d8e5e5"/>
+ <dia:color val="#d8e5e5ff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -3035,7 +3121,7 @@
<dia:real val="17.055"/>
</dia:attribute>
<dia:attribute name="elem_height">
- <dia:real val="16"/>
+ <dia:real val="16.000000000000004"/>
</dia:attribute>
<dia:attribute name="name">
<dia:string>#Report#</dia:string>
@@ -3076,17 +3162,20 @@
<dia:attribute name="comment_tagging">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="line_width">
<dia:real val="0.029999999999999999"/>
</dia:attribute>
<dia:attribute name="line_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="fill_color">
- <dia:color val="#d8e5e5"/>
+ <dia:color val="#d8e5e5ff"/>
</dia:attribute>
<dia:attribute name="text_color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="normal_font">
<dia:font family="monospace" style="0" name="Courier"/>
@@ -3225,6 +3314,29 @@
<dia:attribute name="templates"/>
</dia:object>
<dia:object type="UML - Association" version="2" id="O17">
+ <dia:attribute name="obj_pos">
+ <dia:point val="14,51.5"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="9.005,51.4293;14.2,55.94"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="orth_points">
+ <dia:point val="14,51.5"/>
+ <dia:point val="14,51.5"/>
+ <dia:point val="14,55.1"/>
+ <dia:point val="9.055,55.1"/>
+ </dia:attribute>
+ <dia:attribute name="orth_orient">
+ <dia:enum val="0"/>
+ <dia:enum val="1"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="orth_autoroute">
+ <dia:boolean val="false"/>
+ </dia:attribute>
<dia:attribute name="name">
<dia:string>##</dia:string>
</dia:attribute>
@@ -3261,20 +3373,350 @@
<dia:attribute name="show_arrow_b">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O15" connection="12"/>
+ <dia:connection handle="1" to="O16" connection="11"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O18">
<dia:attribute name="obj_pos">
- <dia:point val="14,51.5"/>
+ <dia:point val="30,31.1"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="9.005,51.5;14.2,55.9"/>
+ <dia:rectangle val="19.7562,31.05;30.2,40.8"/>
</dia:attribute>
<dia:attribute name="meta">
<dia:composite type="dict"/>
</dia:attribute>
<dia:attribute name="orth_points">
- <dia:point val="14,51.5"/>
- <dia:point val="14,51.5"/>
- <dia:point val="14,55.1"/>
- <dia:point val="9.055,55.1"/>
+ <dia:point val="30,31.1"/>
+ <dia:point val="30,33"/>
+ <dia:point val="19.8062,33"/>
+ <dia:point val="19.8062,40"/>
+ </dia:attribute>
+ <dia:attribute name="orth_orient">
+ <dia:enum val="1"/>
+ <dia:enum val="0"/>
+ <dia:enum val="1"/>
+ </dia:attribute>
+ <dia:attribute name="orth_autoroute">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="name">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="direction">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_direction">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="assoc_type">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="role_a">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="multipicity_a">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility_a">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_arrow_a">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="role_b">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="multipicity_b">
+ <dia:string>#*#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility_b">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_arrow_b">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O0" connection="26"/>
+ <dia:connection handle="1" to="O15" connection="1"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Class" version="0" id="O19">
+ <dia:attribute name="obj_pos">
+ <dia:point val="54,40"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="53.985,39.985;66.45,55.615"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="54,40"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="12.434999999999999"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="15.600000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="name">
+ <dia:string>#Review#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="stereotype">
+ <dia:string>#Resource#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>#Users' reviews#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="abstract">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="suppress_attributes">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="suppress_operations">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="visible_attributes">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="visible_operations">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="visible_comments">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="wrap_operations">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="wrap_after_char">
+ <dia:int val="35"/>
+ </dia:attribute>
+ <dia:attribute name="comment_line_length">
+ <dia:int val="35"/>
+ </dia:attribute>
+ <dia:attribute name="comment_tagging">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="allow_resizing">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.029999999999999999"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="fill_color">
+ <dia:color val="#d9e6e6ff"/>
+ </dia:attribute>
+ <dia:attribute name="text_color">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="normal_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="abstract_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="polymorphic_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="classname_font">
+ <dia:font family="sans" style="80" name="Helvetica-Bold"/>
+ </dia:attribute>
+ <dia:attribute name="abstract_classname_font">
+ <dia:font family="sans" style="88" name="Helvetica-BoldOblique"/>
+ </dia:attribute>
+ <dia:attribute name="comment_font">
+ <dia:font family="sans" style="8" name="Helvetica-Oblique"/>
+ </dia:attribute>
+ <dia:attribute name="normal_font_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="polymorphic_font_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="abstract_font_height">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="classname_font_height">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="abstract_classname_font_height">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="comment_font_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="attributes">
+ <dia:composite type="umlattribute">
+ <dia:attribute name="name">
+ <dia:string>#context#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#Context [R WN]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="value">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>#The Context this Feedback belongs to#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="abstract">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="class_scope">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ <dia:composite type="umlattribute">
+ <dia:attribute name="name">
+ <dia:string>#artifact#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#Artifact [R WN]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="value">
+ <dia:string>#""#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>#If specified, the Review was created for an Artifact#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="abstract">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="class_scope">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ <dia:composite type="umlattribute">
+ <dia:attribute name="name">
+ <dia:string>#title#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#str [R WN F I]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="value">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>#One line summary#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="abstract">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="class_scope">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ <dia:composite type="umlattribute">
+ <dia:attribute name="name">
+ <dia:string>#content#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#wikitext [R WN F I]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="value">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>#The content of the Review#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="abstract">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="class_scope">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ <dia:composite type="umlattribute">
+ <dia:attribute name="name">
+ <dia:string>#rating#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="type">
+ <dia:string>#int [R WN S]#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="value">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="comment">
+ <dia:string>#Reviewer' rating, value from 1 to 5.#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="abstract">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="class_scope">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="operations"/>
+ <dia:attribute name="template">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="templates"/>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O20">
+ <dia:attribute name="obj_pos">
+ <dia:point val="48.6525,33.1"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="48.6025,32.34;60.2675,40.84"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="orth_points">
+ <dia:point val="48.6525,33.1"/>
+ <dia:point val="60,33.1"/>
+ <dia:point val="60,40"/>
+ <dia:point val="60.2175,40"/>
</dia:attribute>
<dia:attribute name="orth_orient">
<dia:enum val="0"/>
@@ -3284,19 +3726,145 @@
<dia:attribute name="orth_autoroute">
<dia:boolean val="false"/>
</dia:attribute>
+ <dia:attribute name="name">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="direction">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_direction">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="assoc_type">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="role_a">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="multipicity_a">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility_a">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_arrow_a">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="role_b">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="multipicity_b">
+ <dia:string>#*#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility_b">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_arrow_b">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
<dia:attribute name="text_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
</dia:attribute>
<dia:attribute name="line_colour">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:connections>
- <dia:connection handle="0" to="O15" connection="12"/>
- <dia:connection handle="1" to="O16" connection="11"/>
+ <dia:connection handle="0" to="O0" connection="29"/>
+ <dia:connection handle="1" to="O19" connection="1"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="UML - Association" version="2" id="O21">
+ <dia:attribute name="obj_pos">
+ <dia:point val="61.565,58"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="59.6325,54.84;61.615,58.84"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="orth_points">
+ <dia:point val="61.565,58"/>
+ <dia:point val="60,58"/>
+ <dia:point val="60,55.6"/>
+ <dia:point val="60.2175,55.6"/>
+ </dia:attribute>
+ <dia:attribute name="orth_orient">
+ <dia:enum val="0"/>
+ <dia:enum val="1"/>
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="orth_autoroute">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="name">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="direction">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_direction">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="assoc_type">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="role_a">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="multipicity_a">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility_a">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_arrow_a">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="role_b">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="multipicity_b">
+ <dia:string>#*#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="visibility_b">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ <dia:attribute name="show_arrow_b">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="text_font">
+ <dia:font family="monospace" style="0" name="Courier"/>
+ </dia:attribute>
+ <dia:attribute name="text_height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="text_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000ff"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O14" connection="1"/>
+ <dia:connection handle="1" to="O19" connection="6"/>
</dia:connections>
</dia:object>
<dia:group>
- <dia:object type="Standard - Box" version="0" id="O18">
+ <dia:attribute name="matrix"/>
+ <dia:object type="Standard - Box" version="0" id="O22">
<dia:attribute name="obj_pos">
<dia:point val="62,8"/>
</dia:attribute>
@@ -3316,7 +3884,7 @@
<dia:real val="0.0010583332689479003"/>
</dia:attribute>
<dia:attribute name="inner_color">
- <dia:color val="#ffffcc"/>
+ <dia:color val="#ffffccff"/>
</dia:attribute>
<dia:attribute name="show_background">
<dia:boolean val="true"/>
@@ -3325,12 +3893,12 @@
<dia:real val="0.5"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O19">
+ <dia:object type="Standard - Text" version="1" id="O23">
<dia:attribute name="obj_pos">
<dia:point val="63,9.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,8.705;71.67,9.4525"/>
+ <dia:rectangle val="63,8.705;71.67,9.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3347,7 +3915,7 @@
<dia:point val="63,9.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3358,12 +3926,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O20">
+ <dia:object type="Standard - Text" version="1" id="O24">
<dia:attribute name="obj_pos">
<dia:point val="63,12.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,11.705;79.725,12.4525"/>
+ <dia:rectangle val="63,11.705;79.725,12.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3380,7 +3948,7 @@
<dia:point val="63,12.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3391,12 +3959,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O21">
+ <dia:object type="Standard - Text" version="1" id="O25">
<dia:attribute name="obj_pos">
<dia:point val="63,13.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,12.705;81.39,13.4525"/>
+ <dia:rectangle val="63,12.705;81.39,13.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3413,7 +3981,7 @@
<dia:point val="63,13.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3424,12 +3992,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O22">
+ <dia:object type="Standard - Text" version="1" id="O26">
<dia:attribute name="obj_pos">
<dia:point val="63,11.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,10.705;76.6375,11.4525"/>
+ <dia:rectangle val="63,10.705;76.6375,11.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3446,7 +4014,7 @@
<dia:point val="63,11.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3457,12 +4025,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O23">
+ <dia:object type="Standard - Text" version="1" id="O27">
<dia:attribute name="obj_pos">
<dia:point val="63,14.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,13.705;80.82,14.4525"/>
+ <dia:rectangle val="63,13.705;80.82,14.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3479,7 +4047,7 @@
<dia:point val="63,14.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3490,12 +4058,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O24">
+ <dia:object type="Standard - Text" version="1" id="O28">
<dia:attribute name="obj_pos">
<dia:point val="63,10.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,9.705;74.7525,10.4525"/>
+ <dia:rectangle val="63,9.705;74.7525,10.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3512,7 +4080,7 @@
<dia:point val="63,10.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3523,12 +4091,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O25">
+ <dia:object type="Standard - Text" version="1" id="O29">
<dia:attribute name="obj_pos">
<dia:point val="63,20"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,19.405;80.41,20.1525"/>
+ <dia:rectangle val="63,19.405;80.41,20.15"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3545,7 +4113,7 @@
<dia:point val="63,20"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3556,12 +4124,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O26">
+ <dia:object type="Standard - Text" version="1" id="O30">
<dia:attribute name="obj_pos">
<dia:point val="63,15.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,14.705;76.82,15.4525"/>
+ <dia:rectangle val="63,14.705;76.82,15.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3578,7 +4146,7 @@
<dia:point val="63,15.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3589,12 +4157,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O27">
+ <dia:object type="Standard - Text" version="1" id="O31">
<dia:attribute name="obj_pos">
<dia:point val="63,16.3"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,15.705;82.6725,16.4525"/>
+ <dia:rectangle val="63,15.705;82.6725,16.45"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3611,7 +4179,7 @@
<dia:point val="63,16.3"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3622,17 +4190,17 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O28">
+ <dia:object type="Standard - Text" version="1" id="O32">
<dia:attribute name="obj_pos">
- <dia:point val="55,7"/>
+ <dia:point val="62,7"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="55,6.405;83.9275,7.1525"/>
+ <dia:rectangle val="62,6.405;84.375,7.15"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
<dia:attribute name="string">
- <dia:string>#Visit http://wiki.sugarlabs.org/go/Platform_Team/Sugar_Network/Objects_model for details.#</dia:string>
+ <dia:string>#See http://wiki.sugarlabs.org/go/Sugar_Network/Resources for details.#</dia:string>
</dia:attribute>
<dia:attribute name="font">
<dia:font family="sans" style="0" name="Helvetica"/>
@@ -3641,10 +4209,10 @@
<dia:real val="0.80000000000000004"/>
</dia:attribute>
<dia:attribute name="pos">
- <dia:point val="55,7"/>
+ <dia:point val="62,7"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3655,12 +4223,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O29">
+ <dia:object type="Standard - Text" version="1" id="O33">
<dia:attribute name="obj_pos">
<dia:point val="63,18.1414"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,17.5464;73.7075,18.2939"/>
+ <dia:rectangle val="63,17.5464;73.7075,18.2914"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3677,7 +4245,7 @@
<dia:point val="63,18.1414"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3688,12 +4256,12 @@
<dia:enum val="3"/>
</dia:attribute>
</dia:object>
- <dia:object type="Standard - Text" version="1" id="O30">
+ <dia:object type="Standard - Text" version="1" id="O34">
<dia:attribute name="obj_pos">
<dia:point val="63,17.2475"/>
</dia:attribute>
<dia:attribute name="obj_bb">
- <dia:rectangle val="63,16.6525;75.62,17.4"/>
+ <dia:rectangle val="63,16.6525;75.62,17.3975"/>
</dia:attribute>
<dia:attribute name="text">
<dia:composite type="text">
@@ -3710,7 +4278,7 @@
<dia:point val="63,17.2475"/>
</dia:attribute>
<dia:attribute name="color">
- <dia:color val="#000000"/>
+ <dia:color val="#000000ff"/>
</dia:attribute>
<dia:attribute name="alignment">
<dia:enum val="0"/>
@@ -3722,444 +4290,5 @@
</dia:attribute>
</dia:object>
</dia:group>
- <dia:object type="UML - Association" version="2" id="O31">
- <dia:attribute name="name">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="direction">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_direction">
- <dia:boolean val="true"/>
- </dia:attribute>
- <dia:attribute name="assoc_type">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="role_a">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="multipicity_a">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility_a">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_arrow_a">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="role_b">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="multipicity_b">
- <dia:string>#*#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility_b">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_arrow_b">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="obj_pos">
- <dia:point val="30,33.1"/>
- </dia:attribute>
- <dia:attribute name="obj_bb">
- <dia:rectangle val="19.7562,32.2;30.2,40.8"/>
- </dia:attribute>
- <dia:attribute name="meta">
- <dia:composite type="dict"/>
- </dia:attribute>
- <dia:attribute name="orth_points">
- <dia:point val="30,33.1"/>
- <dia:point val="30,33"/>
- <dia:point val="19.8062,33"/>
- <dia:point val="19.8062,40"/>
- </dia:attribute>
- <dia:attribute name="orth_orient">
- <dia:enum val="1"/>
- <dia:enum val="0"/>
- <dia:enum val="1"/>
- </dia:attribute>
- <dia:attribute name="orth_autoroute">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O0" connection="28"/>
- <dia:connection handle="1" to="O15" connection="1"/>
- </dia:connections>
- </dia:object>
- <dia:object type="UML - Class" version="0" id="O32">
- <dia:attribute name="obj_pos">
- <dia:point val="54,40"/>
- </dia:attribute>
- <dia:attribute name="obj_bb">
- <dia:rectangle val="53.985,39.985;66.45,55.615"/>
- </dia:attribute>
- <dia:attribute name="elem_corner">
- <dia:point val="54,40"/>
- </dia:attribute>
- <dia:attribute name="elem_width">
- <dia:real val="12.435"/>
- </dia:attribute>
- <dia:attribute name="elem_height">
- <dia:real val="15.6"/>
- </dia:attribute>
- <dia:attribute name="name">
- <dia:string>#Review#</dia:string>
- </dia:attribute>
- <dia:attribute name="stereotype">
- <dia:string>#Resource#</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#Users' reviews#</dia:string>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="suppress_attributes">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="suppress_operations">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="visible_attributes">
- <dia:boolean val="true"/>
- </dia:attribute>
- <dia:attribute name="visible_operations">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="visible_comments">
- <dia:boolean val="true"/>
- </dia:attribute>
- <dia:attribute name="wrap_operations">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="wrap_after_char">
- <dia:int val="35"/>
- </dia:attribute>
- <dia:attribute name="comment_line_length">
- <dia:int val="35"/>
- </dia:attribute>
- <dia:attribute name="comment_tagging">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="line_width">
- <dia:real val="0.029999999999999999"/>
- </dia:attribute>
- <dia:attribute name="line_color">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="fill_color">
- <dia:color val="#d9e6e6"/>
- </dia:attribute>
- <dia:attribute name="text_color">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="normal_font">
- <dia:font family="monospace" style="0" name="Courier"/>
- </dia:attribute>
- <dia:attribute name="abstract_font">
- <dia:font family="monospace" style="0" name="Courier"/>
- </dia:attribute>
- <dia:attribute name="polymorphic_font">
- <dia:font family="monospace" style="0" name="Courier"/>
- </dia:attribute>
- <dia:attribute name="classname_font">
- <dia:font family="sans" style="80" name="Helvetica-Bold"/>
- </dia:attribute>
- <dia:attribute name="abstract_classname_font">
- <dia:font family="sans" style="88" name="Helvetica-BoldOblique"/>
- </dia:attribute>
- <dia:attribute name="comment_font">
- <dia:font family="sans" style="8" name="Helvetica-Oblique"/>
- </dia:attribute>
- <dia:attribute name="normal_font_height">
- <dia:real val="0.80000000000000004"/>
- </dia:attribute>
- <dia:attribute name="polymorphic_font_height">
- <dia:real val="0.80000000000000004"/>
- </dia:attribute>
- <dia:attribute name="abstract_font_height">
- <dia:real val="1"/>
- </dia:attribute>
- <dia:attribute name="classname_font_height">
- <dia:real val="1"/>
- </dia:attribute>
- <dia:attribute name="abstract_classname_font_height">
- <dia:real val="1"/>
- </dia:attribute>
- <dia:attribute name="comment_font_height">
- <dia:real val="0.80000000000000004"/>
- </dia:attribute>
- <dia:attribute name="attributes">
- <dia:composite type="umlattribute">
- <dia:attribute name="name">
- <dia:string>#context#</dia:string>
- </dia:attribute>
- <dia:attribute name="type">
- <dia:string>#Context [R WN]#</dia:string>
- </dia:attribute>
- <dia:attribute name="value">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#The Context this Feedback belongs to#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="class_scope">
- <dia:boolean val="false"/>
- </dia:attribute>
- </dia:composite>
- <dia:composite type="umlattribute">
- <dia:attribute name="name">
- <dia:string>#artifact#</dia:string>
- </dia:attribute>
- <dia:attribute name="type">
- <dia:string>#Artifact [R WN]#</dia:string>
- </dia:attribute>
- <dia:attribute name="value">
- <dia:string>#""#</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#If specified, the Review was created for an Artifact#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="class_scope">
- <dia:boolean val="false"/>
- </dia:attribute>
- </dia:composite>
- <dia:composite type="umlattribute">
- <dia:attribute name="name">
- <dia:string>#title#</dia:string>
- </dia:attribute>
- <dia:attribute name="type">
- <dia:string>#str [R WN F I]#</dia:string>
- </dia:attribute>
- <dia:attribute name="value">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#One line summary#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="class_scope">
- <dia:boolean val="false"/>
- </dia:attribute>
- </dia:composite>
- <dia:composite type="umlattribute">
- <dia:attribute name="name">
- <dia:string>#content#</dia:string>
- </dia:attribute>
- <dia:attribute name="type">
- <dia:string>#wikitext [R WN F I]#</dia:string>
- </dia:attribute>
- <dia:attribute name="value">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#The content of the Review#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="class_scope">
- <dia:boolean val="false"/>
- </dia:attribute>
- </dia:composite>
- <dia:composite type="umlattribute">
- <dia:attribute name="name">
- <dia:string>#rating#</dia:string>
- </dia:attribute>
- <dia:attribute name="type">
- <dia:string>#int [R WN S]#</dia:string>
- </dia:attribute>
- <dia:attribute name="value">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="comment">
- <dia:string>#Reviewer' rating, value from 1 to 5.#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="abstract">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="class_scope">
- <dia:boolean val="false"/>
- </dia:attribute>
- </dia:composite>
- </dia:attribute>
- <dia:attribute name="operations"/>
- <dia:attribute name="template">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="templates"/>
- </dia:object>
- <dia:object type="UML - Association" version="2" id="O33">
- <dia:attribute name="name">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="direction">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_direction">
- <dia:boolean val="true"/>
- </dia:attribute>
- <dia:attribute name="assoc_type">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="role_a">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="multipicity_a">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility_a">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_arrow_a">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="role_b">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="multipicity_b">
- <dia:string>#*#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility_b">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_arrow_b">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="obj_pos">
- <dia:point val="48.6525,35.1"/>
- </dia:attribute>
- <dia:attribute name="obj_bb">
- <dia:rectangle val="48.6025,34.3;60.2675,40.8"/>
- </dia:attribute>
- <dia:attribute name="meta">
- <dia:composite type="dict"/>
- </dia:attribute>
- <dia:attribute name="orth_points">
- <dia:point val="48.6525,35.1"/>
- <dia:point val="60,35.1"/>
- <dia:point val="60,40"/>
- <dia:point val="60.2175,40"/>
- </dia:attribute>
- <dia:attribute name="orth_orient">
- <dia:enum val="0"/>
- <dia:enum val="1"/>
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="orth_autoroute">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O0" connection="31"/>
- <dia:connection handle="1" to="O32" connection="1"/>
- </dia:connections>
- </dia:object>
- <dia:object type="UML - Association" version="2" id="O34">
- <dia:attribute name="name">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="direction">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_direction">
- <dia:boolean val="true"/>
- </dia:attribute>
- <dia:attribute name="assoc_type">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="role_a">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="multipicity_a">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility_a">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_arrow_a">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="role_b">
- <dia:string>##</dia:string>
- </dia:attribute>
- <dia:attribute name="multipicity_b">
- <dia:string>#*#</dia:string>
- </dia:attribute>
- <dia:attribute name="visibility_b">
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="show_arrow_b">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="obj_pos">
- <dia:point val="61.565,58"/>
- </dia:attribute>
- <dia:attribute name="obj_bb">
- <dia:rectangle val="59.6325,54.8;61.615,58.8"/>
- </dia:attribute>
- <dia:attribute name="meta">
- <dia:composite type="dict"/>
- </dia:attribute>
- <dia:attribute name="orth_points">
- <dia:point val="61.565,58"/>
- <dia:point val="60,58"/>
- <dia:point val="60,55.6"/>
- <dia:point val="60.2175,55.6"/>
- </dia:attribute>
- <dia:attribute name="orth_orient">
- <dia:enum val="0"/>
- <dia:enum val="1"/>
- <dia:enum val="0"/>
- </dia:attribute>
- <dia:attribute name="orth_autoroute">
- <dia:boolean val="false"/>
- </dia:attribute>
- <dia:attribute name="text_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:attribute name="line_colour">
- <dia:color val="#000000"/>
- </dia:attribute>
- <dia:connections>
- <dia:connection handle="0" to="O14" connection="1"/>
- <dia:connection handle="1" to="O32" connection="6"/>
- </dia:connections>
- </dia:object>
</dia:layer>
</dia:diagram>
diff --git a/sugar_network/client/cache.py b/sugar_network/client/cache.py
index e0d8c94..6c91b17 100644
--- a/sugar_network/client/cache.py
+++ b/sugar_network/client/cache.py
@@ -23,7 +23,7 @@ from os.path import exists, join, isdir
from sugar_network.client import IPCClient, local_root
from sugar_network.client import cache_limit, cache_lifetime
from sugar_network.toolkit.bundle import Bundle
-from sugar_network.toolkit import pipe, util, enforce
+from sugar_network.toolkit import pipe, util, exception, enforce
_logger = logging.getLogger('cache')
@@ -122,7 +122,7 @@ def _list():
# Negative `unpack_size` to process large impls at first
result.append((os.stat(path).st_mtime, -unpack_size, path))
except Exception:
- util.exception('Cannot list %r cached implementation', path)
+ exception('Cannot list %r cached implementation', path)
result.append((0, 0, path))
return total, sorted(result)
diff --git a/sugar_network/client/clones.py b/sugar_network/client/clones.py
index 1a977bd..07114f3 100644
--- a/sugar_network/client/clones.py
+++ b/sugar_network/client/clones.py
@@ -140,7 +140,7 @@ class _Inotify(Inotify):
exception(_logger, 'Cannot read %r spec', clone_path)
return
- context = spec['implement']
+ context = spec['context']
context_path = _context_path(context, hashed_path)
_ensure_path(context_path)
diff --git a/sugar_network/client/commands.py b/sugar_network/client/commands.py
index 404ddf9..d20b2aa 100644
--- a/sugar_network/client/commands.py
+++ b/sugar_network/client/commands.py
@@ -464,7 +464,7 @@ class ClientCommands(db.CommandsProcessor, Commands, journal.Commands):
else:
copy = self._node_call(method='GET', document='context', guid=guid,
reply=[
- 'type', 'implement', 'title', 'summary', 'description',
+ 'type', 'title', 'summary', 'description',
'homepage', 'mime_types', 'dependencies',
])
copy.update(props)
diff --git a/sugar_network/client/injector.py b/sugar_network/client/injector.py
index c180c05..02c7937 100644
--- a/sugar_network/client/injector.py
+++ b/sugar_network/client/injector.py
@@ -21,7 +21,7 @@ from os.path import join, exists, basename, dirname
from sugar_network import client
from sugar_network.client import journal, cache
-from sugar_network.toolkit import http, pipe, lsb_release, util, enforce
+from sugar_network.toolkit import pipe, lsb_release, util
_PMS_PATHS = {
@@ -152,18 +152,11 @@ def _clone_impl(context_guid, params):
conn = client.IPCClient()
context = conn.get(['context', context_guid], reply=['title'])
+ impl = conn.meta(['context', context_guid], cmd='clone', **params)
- impls = conn.get(['implementation'], context=context_guid,
- order_by='-version', limit=1,
- reply=['guid', 'version', 'stability', 'spec'],
- **params)['result']
- enforce(impls, http.NotFound, 'No implementations')
- impl = impls[0]
-
- spec = impl['spec']['*-*']
src_path = cache.get(impl['guid'], impl)
- if 'extract' in spec:
- src_path = join(src_path, spec['extract'])
+ if 'extract' in impl:
+ src_path = join(src_path, impl['extract'])
dst_path = util.unique_filename(
client.activity_dirs.value[0], basename(src_path))
@@ -178,7 +171,7 @@ def _clone_impl(context_guid, params):
'stability': impl['stability'],
'spec': join(dst_path, 'activity', 'activity.info'),
'path': dst_path,
- 'command': spec['commands']['activity']['exec'].split(),
+ 'command': impl['commands']['activity']['exec'].split(),
}])
diff --git a/sugar_network/client/solver.py b/sugar_network/client/solver.py
index 14816a6..10245a1 100644
--- a/sugar_network/client/solver.py
+++ b/sugar_network/client/solver.py
@@ -13,6 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# pylint: disable-msg=W0611,F0401,W0201,E1101,W0232
+
import sys
import logging
from os.path import isabs, join, dirname
@@ -28,7 +30,6 @@ from zeroinstall.injector.config import Config
from zeroinstall.injector.driver import Driver
from zeroinstall.injector.requirements import Requirements
from zeroinstall.injector.arch import machine_ranks
-# pylint: disable-msg=W0611
from zeroinstall.injector.distro import try_cleanup_distro_version
diff --git a/sugar_network/db/router.py b/sugar_network/db/router.py
index dea8a6b..f7f4b96 100644
--- a/sugar_network/db/router.py
+++ b/sugar_network/db/router.py
@@ -175,18 +175,20 @@ class Router(object):
result_streamed = isinstance(result, types.GeneratorType)
- if request['method'] != 'HEAD':
- if js_callback:
- if result_streamed:
- result = ''.join(result)
- result_streamed = False
- result = '%s(%s);' % (js_callback, json.dumps(result))
- response.content_length = len(result)
- elif not result_streamed:
- if response.content_type == 'application/json':
- result = json.dumps(result)
- if 'content-length' not in response:
- response.content_length = len(result) if result else 0
+ if request['method'] == 'HEAD':
+ result_streamed = False
+ result = None
+ elif js_callback:
+ if result_streamed:
+ result = ''.join(result)
+ result_streamed = False
+ result = '%s(%s);' % (js_callback, json.dumps(result))
+ response.content_length = len(result)
+ elif not result_streamed:
+ if response.content_type == 'application/json':
+ result = json.dumps(result)
+ if 'content-length' not in response:
+ response.content_length = len(result) if result else 0
for key, value in response.meta.items():
response.set('X-SN-%s' % str(key), json.dumps(value))
@@ -196,7 +198,9 @@ class Router(object):
start_response(response.status, response.items())
- if result_streamed:
+ if request['method'] == 'HEAD':
+ enforce(result is None, 'HEAD responses should not contain body')
+ elif result_streamed:
for i in result:
yield i
elif result is not None:
diff --git a/sugar_network/node/commands.py b/sugar_network/node/commands.py
index 7678d25..d0555b9 100644
--- a/sugar_network/node/commands.py
+++ b/sugar_network/node/commands.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 Aleksey Lim
+# Copyright (C) 2012-2013 Aleksey Lim
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -21,6 +21,7 @@ from os.path import join, isdir, exists
from sugar_network import db, node, static
from sugar_network.node import auth, stats_node
from sugar_network.resources.volume import Commands
+from sugar_network.toolkit.spec import parse_requires, ensure_requires
from sugar_network.toolkit import http, util, coroutine, exception, enforce
@@ -51,7 +52,7 @@ class NodeCommands(db.VolumeCommands, Commands):
@db.route('GET', '/robots.txt')
def robots(self, request, response):
response.content_type = 'text/plain'
- return _ROBOTS_TXT
+ return 'User-agent: *\nDisallow: /\n'
@db.route('GET', '/favicon.ico')
def favicon(self, request, response):
@@ -59,10 +60,6 @@ class NodeCommands(db.VolumeCommands, Commands):
blob=join(static.PATH, 'favicon.ico'),
mime_type='image/x-icon')
- @db.volume_command(method='GET', mime_type='text/html')
- def hello(self):
- return _HELLO_HTML
-
@db.route('GET', '/packages')
def route_packages(self, request, response):
enforce(node.files_root.value, http.BadRequest, 'Disabled')
@@ -92,6 +89,10 @@ class NodeCommands(db.VolumeCommands, Commands):
else:
return util.iter_file(path)
+ @db.volume_command(method='GET')
+ def hello(self, request, response):
+ raise http.Redirect('http://wiki.sugarlabs.org/go/Sugar_Network/API')
+
@db.volume_command(method='GET', cmd='stat',
mime_type='application/json')
def stat(self):
@@ -190,17 +191,18 @@ class NodeCommands(db.VolumeCommands, Commands):
@db.document_command(method='GET', cmd='clone',
arguments={'requires': db.to_list})
- def clone(self, document, guid, version, requires, stability='stable'):
- enforce(document == 'context', 'No way to clone')
- request = db.Request(method='GET', document='implementation',
- context=guid, version=version, stability=stability,
- requires=requires, order_by='-version', limit=1,
- reply=['guid'])
- impls = self.call(request, db.Response())['result']
- enforce(impls, http.NotFound, 'No implementations found')
- request = db.Request(method='GET', document='implementation',
- guid=impls[0]['guid'], prop='data')
- return self.call(request, db.Response())
+ def clone(self, request, response):
+ impl = self._clone(request)
+ return self.get_prop('implementation', impl.guid, 'data',
+ request, response)
+
+ @db.document_command(method='HEAD', cmd='clone',
+ arguments={'requires': db.to_list})
+ def meta_clone(self, request, response):
+ impl = self._clone(request)
+ props = impl.properties(['guid', 'license', 'version', 'stability'])
+ response.meta.update(props)
+ response.meta.update(impl.meta('data')['spec']['*-*'])
@db.document_command(method='GET', cmd='deplist',
mime_type='application/json', arguments={'requires': db.to_list})
@@ -249,7 +251,7 @@ class NodeCommands(db.VolumeCommands, Commands):
impls, __ = implementations.find(limit=db.MAX_LIMIT,
context=context.guid, layer=layer)
for impl in impls:
- for arch, spec in impl['spec'].items():
+ for arch, spec in impl.meta('data')['spec'].items():
spec['guid'] = impl.guid
spec['version'] = impl['version']
spec['arch'] = arch
@@ -260,7 +262,6 @@ class NodeCommands(db.VolumeCommands, Commands):
requires.setdefault(i, {})
blob = implementations.get(impl.guid).meta('data')
if blob:
- spec['mime_type'] = blob.get('mime_type')
spec['blob_size'] = blob.get('blob_size')
spec['unpack_size'] = blob.get('unpack_size')
versions.append(spec)
@@ -352,6 +353,33 @@ class NodeCommands(db.VolumeCommands, Commands):
coroutine.sleep(stats_node.stats_node_step.value)
self._stats.commit()
+ def _clone(self, request):
+ enforce(request['document'] == 'context', 'No way to clone')
+
+ requires = {}
+ if 'requires' in request.query:
+ for i in request['requires']:
+ requires.update(parse_requires(i))
+ request.query.pop('requires')
+ else:
+ request.query['limit'] = 1
+
+ if 'stability' not in request.query:
+ request.query['stability'] = 'stable'
+
+ impls, __ = self.volume['implementation'].find(
+ context=request['guid'], order_by='-version', **request.query)
+ impl = None
+ for impl in impls:
+ if requires:
+ impl_deps = impl.meta('data')['spec']['*-*']['requires']
+ if not ensure_requires(impl_deps, requires):
+ continue
+ break
+ else:
+ raise http.NotFound('No implementations found')
+ return impl
+
def _load_pubkey(pubkey):
pubkey = pubkey.strip()
@@ -374,15 +402,3 @@ def _load_pubkey(pubkey):
raise http.Forbidden(message)
return str(hashlib.sha1(pubkey.split()[1]).hexdigest()), pubkey_pkcs8
-
-
-_HELLO_HTML = """\
-<h2>Welcome to Sugar Network API!</h2>
-Consult <a href="http://wiki.sugarlabs.org/go/Platform_Team/Sugar_Network/API">
-Sugar Labs Wiki</a> to learn how it can be used.
-"""
-
-_ROBOTS_TXT = """\
-User-agent: *
-Disallow: /
-"""
diff --git a/sugar_network/resources/context.py b/sugar_network/resources/context.py
index ee8387b..4d30776 100644
--- a/sugar_network/resources/context.py
+++ b/sugar_network/resources/context.py
@@ -36,11 +36,6 @@ class Context(Resource):
self['layer'] = tuple(self['layer']) + ('common',)
return value
- @db.indexed_property(prefix='M',
- full_text=True, default=[], typecast=[])
- def implement(self, value):
- return value
-
@db.indexed_property(slot=1, prefix='S', full_text=True, localized=True)
def title(self, value):
return value
diff --git a/sugar_network/resources/implementation.py b/sugar_network/resources/implementation.py
index 4abcd02..d915473 100644
--- a/sugar_network/resources/implementation.py
+++ b/sugar_network/resources/implementation.py
@@ -13,39 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# pylint: disable-msg=E1101,E0102,E0202
-
-import os
-from os.path import exists
-
import xapian
from sugar_network import db, resources
from sugar_network.resources.volume import Resource
from sugar_network.toolkit.licenses import GOOD_LICENSES
-from sugar_network.toolkit.bundle import Bundle
-from sugar_network.toolkit import http, util, enforce
-
-
-_ASLO_URL = 'http://download.sugarlabs.org/activities'
-_ASLO_PATH = '/upload/activities'
-
-
-def _encode_version(version):
- version = util.parse_version(version)
- # Convert to [(`version`, `modifier`)]
- version = zip(*([iter(version)] * 2))
- major, modifier = version.pop(0)
-
- result = sum([(rank % 10000) * pow(10000, 3 - i)
- for i, rank in enumerate((major + [0, 0])[:3])])
- result += (5 + modifier) * 1000
- if modifier and version:
- minor, __ = version.pop(0)
- if minor:
- result += (minor[0] % 1000)
-
- return xapian.sortable_serialise(result)
+from sugar_network.toolkit.spec import parse_version
+from sugar_network.toolkit import http, enforce
class Implementation(Resource):
@@ -67,7 +41,8 @@ class Implementation(Resource):
def license(self, value):
return value
- @db.indexed_property(slot=1, prefix='V', reprcast=_encode_version,
+ @db.indexed_property(slot=1, prefix='V',
+ reprcast=lambda x: _encode_version(x),
permissions=db.ACCESS_CREATE | db.ACCESS_READ)
def version(self, value):
return value
@@ -78,55 +53,28 @@ class Implementation(Resource):
def stability(self, value):
return value
- @db.indexed_property(prefix='R', typecast=[], default=[],
- permissions=db.ACCESS_CREATE | db.ACCESS_READ)
- def requires(self, value):
- return value
-
@db.indexed_property(prefix='N', full_text=True, localized=True,
- permissions=db.ACCESS_CREATE | db.ACCESS_READ)
+ default='', permissions=db.ACCESS_CREATE | db.ACCESS_READ)
def notes(self, value):
return value
- @db.stored_property(typecast=dict, default={})
- def spec(self, value):
- return value
-
@db.blob_property()
def data(self, value):
- if value:
- context = self.volume['context'].get(self['context'])
- value['name'] = [context['title'], self['version']]
return value
- @data.setter
- def data(self, value):
- context = self.volume['context'].get(self['context'])
- if 'activity' not in context['type']:
- return value
- def calc_unpack_size(path):
- unpack_size = 0
- with Bundle(path, mime_type='application/zip') as bundle:
- for arcname in bundle.get_names():
- unpack_size += bundle.getmember(arcname).size
- value['unpack_size'] = unpack_size
+def _encode_version(version):
+ version = parse_version(version)
+ # Convert to [(`version`, `modifier`)]
+ version = zip(*([iter(version)] * 2))
+ major, modifier = version.pop(0)
- if 'unpack_size' not in value:
- if 'blob' in value:
- calc_unpack_size(value['blob'])
- elif 'url' in value:
- url = value['url']
- if url.startswith(_ASLO_URL):
- local_path = _ASLO_PATH + url[len(_ASLO_URL):]
- if exists(local_path):
- calc_unpack_size(local_path)
- value['blob_size'] = os.stat(local_path).st_size
- if 'unpack_size' not in value:
- with util.NamedTemporaryFile() as f:
- http.download(url, f.name)
- value['blob_size'] = os.stat(f.name).st_size
- calc_unpack_size(f.name)
+ result = sum([(rank % 10000) * pow(10000, 3 - i)
+ for i, rank in enumerate((major + [0, 0])[:3])])
+ result += (5 + modifier) * 1000
+ if modifier and version:
+ minor, __ = version.pop(0)
+ if minor:
+ result += (minor[0] % 1000)
- value['mime_type'] = 'application/vnd.olpc-sugar'
- return value
+ return xapian.sortable_serialise(result)
diff --git a/sugar_network/toolkit/http.py b/sugar_network/toolkit/http.py
index 9e66e23..30eb59e 100644
--- a/sugar_network/toolkit/http.py
+++ b/sugar_network/toolkit/http.py
@@ -132,6 +132,16 @@ class Client(object):
response = self.request('GET', path_, params=kwargs)
return self._decode_reply(response)
+ def meta(self, path_=None, **kwargs):
+ response = self.request('HEAD', path_, params=kwargs)
+ result = {}
+ for key, value in response.headers.items():
+ if key.startswith('x-sn-'):
+ result[key[5:]] = json.loads(value)
+ else:
+ result[key] = value
+ return result
+
def post(self, path_=None, data_=None, **kwargs):
response = self.request('POST', path_, json.dumps(data_),
headers={'Content-Type': 'application/json'}, params=kwargs)
@@ -196,7 +206,7 @@ class Client(object):
return response
content = response.content
try:
- error = json.loads(content)
+ error = json.loads(content)['error']
except Exception:
# On non-JSONified fail response, assume that the error
# was not sent by the application level server code, i.e.,
@@ -204,18 +214,13 @@ class Client(object):
# If so, try to resend request.
if a_try <= self._max_retries and method == 'GET':
continue
- _logger.trace('Request failed, '
- 'method=%s path=%r params=%r headers=%r '
- 'status_code=%s content=%s',
- method, path, params, headers,
- response.status_code,
- '\n' + content if content else None)
- response.raise_for_status()
- else:
- for cls in _FORWARD_STATUSES:
- if response.status_code == cls.status_code:
- raise cls(error['error'])
- raise RuntimeError(error['error'])
+ error = content or 'No error message provided'
+ _logger.trace('Request failed, method=%s path=%r params=%r '
+ 'headers=%r status_code=%s error=%s',
+ method, path, params, headers, response.status_code,
+ '\n' + error)
+ cls = _FORWARD_STATUSES.get(response.status_code, RuntimeError)
+ raise cls(error)
return response
@@ -277,10 +282,11 @@ class Client(object):
del reply.headers['transfer-encoding']
response.update(reply.headers)
- if reply.headers.get('Content-Type') == 'application/json':
- return json.loads(reply.content)
- else:
- return reply.raw
+ if method != 'HEAD':
+ if reply.headers.get('Content-Type') == 'application/json':
+ return json.loads(reply.content)
+ else:
+ return reply.raw
def subscribe(self, **condition):
return _Subscription(self, condition)
@@ -349,9 +355,9 @@ def _sign(key_path, data):
return key.sign_asn1(hashlib.sha1(data).digest()).encode('hex')
-_FORWARD_STATUSES = [
- BadRequest,
- Forbidden,
- NotFound,
- ServiceUnavailable,
- ]
+_FORWARD_STATUSES = {
+ BadRequest.status_code: BadRequest,
+ Forbidden.status_code: Forbidden,
+ NotFound.status_code: NotFound,
+ ServiceUnavailable.status_code: ServiceUnavailable,
+ }
diff --git a/sugar_network/toolkit/spec.py b/sugar_network/toolkit/spec.py
index 91afc0d..b914c5c 100644
--- a/sugar_network/toolkit/spec.py
+++ b/sugar_network/toolkit/spec.py
@@ -15,6 +15,7 @@
import re
import os
+import sys
import logging
from os.path import join, exists, dirname
from ConfigParser import ConfigParser
@@ -27,7 +28,7 @@ EMPTY_LICENSE = 'License is not specified'
_FIELDS = {
# name: (required, typecast)
- 'implement': (True, None),
+ 'context': (True, None),
'name': (True, None),
'summary': (True, None),
'description': (False, None),
@@ -44,7 +45,7 @@ _STABILITIES = ('insecure', 'buggy', 'developer', 'testing', 'stable')
_POLICY_URL = 'http://wiki.sugarlabs.org/go/Sugar_Network/Policy'
_LIST_SEPARATOR = ';'
-_RESTRICTION_RE = re.compile('(>=|<|=)\\s*([0-9.]+)')
+_RESTRICTION_RE = re.compile('(<|<=|=|>|>=)\\s*([0-9.]+)')
_VERSION_RE = re.compile('-([a-z]*)')
_VERSION_MOD_TO_VALUE = {
@@ -130,7 +131,7 @@ def format_version(version):
return ''.join(version)
-def format_next_version(version):
+def format_next_version(version, deep=True):
"""Convert incremented version to string representation.
Before convertation, the last version's rank will be incremented.
@@ -142,10 +143,80 @@ def format_next_version(version):
return None
if isinstance(version, basestring):
version = parse_version(version)
- version[-2][-1] += 1
+ if deep:
+ version[-2] += [1]
+ else:
+ version[-2][-1] += 1
return format_version(version)
+def parse_requires(requires):
+ result = {}
+
+ for dep_str in _parse_list(requires):
+ dep = _Dependency()
+
+ if dep_str.startswith('[') and dep_str.endswith(']'):
+ dep_str = dep_str[1:-1]
+ dep['importance'] = 'recommended'
+
+ parts = _RESTRICTION_RE.split(dep_str)
+ enforce(parts[0], 'Can parse dependency from "%s" string', dep_str)
+
+ dep_name = parts.pop(0).strip()
+ if dep_name in result:
+ result[dep_name].update(dep)
+ dep = result[dep_name]
+ else:
+ result[dep_name] = dep
+
+ not_before = None
+ before = None
+ while len(parts) >= 3:
+ if parts[0] == '<':
+ before = format_version(parts[1])
+ elif parts[0] == '<=':
+ before = format_next_version(parts[1])
+ elif parts[0] == '>':
+ not_before = format_next_version(parts[1])
+ elif parts[0] == '>=':
+ not_before = format_version(parts[1])
+ elif parts[0] == '=':
+ not_before = format_version(parts[1])
+ before = format_next_version(parts[1], False)
+ del parts[:3]
+
+ enforce(not parts or not parts[0].strip(),
+ 'Cannot parse "%s", it should be in format '
+ '"<dependency> (>=|<|=) <version>"', dep_str)
+
+ if before or not_before:
+ dep.setdefault('restrictions', [])
+ dep['restrictions'].append((not_before, before))
+
+ return result
+
+
+def ensure_requires(to_consider, to_apply):
+
+ def intersect(x, y):
+ l = max([parse_version(i) for i, __ in (x + y)])
+ r = min([[[sys.maxint]] if i is None else parse_version(i) \
+ for __, i in [x + y]])
+ return l is None or r is None or l < r
+
+ for name, cond in to_apply.items():
+ dep = to_consider.get(name)
+ if dep is None:
+ return False
+ if 'restrictions' not in dep or 'restrictions' not in cond:
+ continue
+ if not intersect(dep['restrictions'], cond['restrictions']):
+ return False
+
+ return True
+
+
class Spec(object):
def __init__(self, spec=None, root=None):
@@ -217,7 +288,7 @@ class Spec(object):
return self._get(section, key)
def __repr__(self):
- return '<Spec %s>' % self['implement']
+ return '<Spec %s>' % self['context']
def _get(self, section, key):
if self._config.has_option(section, key):
@@ -227,7 +298,7 @@ class Spec(object):
for section in sorted(self._config.sections()):
bindings = _parse_bindings(self._get(section, 'binding'))
self.bindings.update(bindings)
- requires = _parse_requires(self._get(section, 'requires'))
+ requires = parse_requires(self._get(section, 'requires'))
section_type = section.split(':')[0]
if section_type == 'Activity':
@@ -270,8 +341,8 @@ class Spec(object):
self._fields[key] = value
if self.activity is not None:
- # TODO Switch to `implement` tag at the end
- self._fields['implement'] = self.activity['bundle_id']
+ # TODO Switch to `context` tag at the end
+ self._fields['context'] = self.activity['bundle_id']
# Do some backwards compatibility expansions for activities
if not self['summary'] and self['name']:
self._fields['summary'] = self['name']
@@ -403,6 +474,8 @@ class _Dependency(dict):
def versions_range(self):
for not_before, before in self.get('restrictions') or []:
+ if not_before is None or before is None:
+ continue
i = parse_version(not_before)[0]
yield format_version([i, 0])
end = parse_version(before)[0]
@@ -437,53 +510,6 @@ def _parse_bindings(text):
return sorted(result)
-def _parse_requires(requires):
- result = {}
-
- for dep_str in _parse_list(requires):
- dep = _Dependency()
-
- if dep_str.startswith('[') and dep_str.endswith(']'):
- dep_str = dep_str[1:-1]
- dep['importance'] = 'recommended'
-
- parts = _RESTRICTION_RE.split(dep_str)
- enforce(parts[0], 'Can parse dependency from "%s" string', dep_str)
-
- dep_name = parts.pop(0).strip()
- if dep_name in result:
- result[dep_name].update(dep)
- dep = result[dep_name]
- else:
- result[dep_name] = dep
-
- not_before = None
- before = None
- while len(parts) >= 3:
- if parts[0] == '<':
- before = format_version(parts[1])
- elif parts[0] == '<=':
- before = format_next_version(parts[1])
- elif parts[0] == '>':
- not_before = format_next_version(parts[1])
- elif parts[0] == '>=':
- not_before = format_version(parts[1])
- elif parts[0] == '=':
- not_before = format_version(parts[1])
- before = format_next_version(parts[1])
- del parts[:3]
-
- enforce(not parts or not parts[0].strip(),
- 'Cannot parse "%s", it should be in format '
- '"<dependency> (>=|<|=) <version>"', dep_str)
-
- if before or not_before:
- dep.setdefault('restrictions', [])
- dep['restrictions'].append((not_before, before))
-
- return result
-
-
def _parse_list(str_list):
if not str_list:
return []
diff --git a/sugar_network/toolkit/util.py b/sugar_network/toolkit/util.py
index 8fc26cf..107235b 100644
--- a/sugar_network/toolkit/util.py
+++ b/sugar_network/toolkit/util.py
@@ -17,6 +17,7 @@
import os
import json
+import errno
import logging
import hashlib
import tempfile
@@ -55,6 +56,8 @@ def init_logging(debug_level):
self._log(9, message, args, **kwargs)
_disable_logger(['sugar_stats'])
else:
+ logging.Logger.trace = lambda self, message, *args, **kwargs: \
+ self._log(9, message, args, **kwargs)
logging.Logger.heartbeat = lambda self, message, *args, **kwargs: \
self._log(8, message, args, **kwargs)
@@ -320,12 +323,30 @@ def TemporaryFile(*args, **kwargs):
return tempfile.TemporaryFile(*args, **kwargs)
-def NamedTemporaryFile(*args, **kwargs):
- if cachedir.value:
- if not exists(cachedir.value):
- os.makedirs(cachedir.value)
- kwargs['dir'] = cachedir.value
- return tempfile.NamedTemporaryFile(*args, **kwargs)
+class NamedTemporaryFile(object):
+
+ def __init__(self, *args, **kwargs):
+ if cachedir.value:
+ if not exists(cachedir.value):
+ os.makedirs(cachedir.value)
+ kwargs['dir'] = cachedir.value
+ self._file = tempfile.NamedTemporaryFile(*args, **kwargs)
+
+ def close(self):
+ try:
+ self._file.close()
+ except OSError, error:
+ if error.errno != errno.ENOENT:
+ raise
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.close()
+
+ def __getattr__(self, name):
+ return getattr(self._file, name)
class Seqno(object):
diff --git a/tests/__init__.py b/tests/__init__.py
index f84325b..84378c6 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -37,7 +37,7 @@ root = abspath(dirname(__file__))
tmproot = '/tmp/sugar_network.tests'
tmpdir = None
-monkey.patch_socket(dns=False)
+monkey.patch_socket()
monkey.patch_select()
monkey.patch_ssl()
monkey.patch_time()
@@ -226,7 +226,11 @@ class Test(unittest.TestCase):
def zips(self, *items):
with util.NamedTemporaryFile() as f:
bundle = zipfile.ZipFile(f.name, 'w')
- for arcname, data in items:
+ for i in items:
+ if isinstance(i, basestring):
+ arcname = data = i
+ else:
+ arcname, data = i
if not isinstance(data, basestring):
data = '\n'.join(data)
bundle.writestr(arcname, data)
diff --git a/tests/units/client/injector.py b/tests/units/client/injector.py
index 11e0067..256cfa4 100755
--- a/tests/units/client/injector.py
+++ b/tests/units/client/injector.py
@@ -60,6 +60,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -67,12 +69,10 @@ Can't find all required implementations:
'exec': 'echo',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'topdir',
},
},
- })
+ }})
pipe = injector.clone(context)
log_path = tests.tmpdir + '/.sugar/default/logs/%s_1.log' % context
@@ -126,6 +126,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -133,17 +135,13 @@ Can't find all required implementations:
'exec': 'true',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'topdir',
},
},
- })
- blob_path = 'master/implementation/%s/%s/data' % (impl[:2], impl)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('topdir/probe', 'probe')
- bundle.close()
+ 'blob': StringIO(self.zips(['topdir/probe', [
+ 'probe',
+ ]])),
+ }})
pipe = injector.clone_impl(context)
log_path = tests.tmpdir + '/.sugar/default/logs/%s.log' % context
@@ -175,6 +173,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -182,17 +182,13 @@ Can't find all required implementations:
'exec': 'echo',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'topdir',
},
},
- })
- blob_path = 'master/implementation/%s/%s/data' % (impl[:2], impl)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('topdir/probe', 'probe')
- bundle.close()
+ 'blob': StringIO(self.zips(['topdir/probe', [
+ 'probe',
+ ]])),
+ }})
for event in injector.clone(context):
pass
@@ -216,6 +212,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -223,26 +221,19 @@ Can't find all required implementations:
'exec': 'true',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'TestActivitry',
},
},
- })
-
- blob_path = 'master/implementation/%s/%s/data' % (impl[:2], impl)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('TestActivitry/activity/activity.info', '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = true',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ]))
- bundle.close()
+ 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivitry',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license=Public Domain',
+ ]])),
+ }})
self.override(journal, 'create_activity_id', lambda: 'activity_id')
pipe = injector.launch(context)
@@ -265,6 +256,8 @@ Can't find all required implementations:
'version': '2',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl_2, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -272,26 +265,19 @@ Can't find all required implementations:
'exec': 'true',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'TestActivitry',
},
},
- })
-
- blob_path = 'master/implementation/%s/%s/data' % (impl_2[:2], impl_2)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('TestActivitry/activity/activity.info', '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = true',
- 'icon = icon',
- 'activity_version = 2',
- 'license=Public Domain',
- ]))
- bundle.close()
+ 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivitry',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license=Public Domain',
+ ]])),
+ }})
shutil.rmtree('cache', ignore_errors=True)
pipe = injector.launch(context)
@@ -353,6 +339,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -360,8 +348,6 @@ Can't find all required implementations:
'exec': 'true',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'topdir',
'requires': {
'dep1': {},
@@ -369,12 +355,10 @@ Can't find all required implementations:
},
},
},
- })
- blob_path = 'master/implementation/%s/%s/data' % (impl[:2], impl)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('topdir/probe', 'probe')
- bundle.close()
+ 'blob': StringIO(self.zips(['topdir/probe', [
+ 'probe',
+ ]])),
+ }})
conn.post(['context'], {
'guid': 'dep1',
@@ -553,6 +537,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -560,21 +546,17 @@ Can't find all required implementations:
'exec': 'echo',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'topdir',
},
},
- })
- blob_path = 'master/implementation/%s/%s/data' % (impl[:2], impl)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('topdir/activity/foo', '')
- bundle.writestr('topdir/bin/bar', '')
- bundle.writestr('topdir/bin/probe', '')
- bundle.writestr('topdir/file1', '')
- bundle.writestr('topdir/test/file2', '')
- bundle.close()
+ 'blob': StringIO(self.zips(
+ 'topdir/activity/foo',
+ 'topdir/bin/bar',
+ 'topdir/bin/probe',
+ 'topdir/file1',
+ 'topdir/test/file2',
+ )),
+ }})
pipe = injector.clone(context)
log_path = tests.tmpdir + '/.sugar/default/logs/%s_2.log' % context
@@ -601,6 +583,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -608,17 +592,13 @@ Can't find all required implementations:
'exec': 'echo',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'topdir',
},
},
- })
- blob_path = 'master/implementation/%s/%s/data' % (impl[:2], impl)
- self.touch((blob_path, json.dumps({})))
- bundle = zipfile.ZipFile(blob_path + '.blob', 'w')
- bundle.writestr('topdir/probe', 'probe')
- bundle.close()
+ 'blob': StringIO(self.zips(['topdir/probe', [
+ 'probe',
+ ]])),
+ }})
for event in injector.clone(context):
pass
@@ -663,6 +643,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -673,6 +655,7 @@ Can't find all required implementations:
'requires': {
'dep2': {'restrictions': [['1', '2']]},
'dep3': {},
+ },
},
},
}})
@@ -740,12 +723,14 @@ Can't find all required implementations:
'summary': 'summary',
'description': 'description',
})
- conn.post(['implementation'], {
+ impl = conn.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -755,6 +740,7 @@ Can't find all required implementations:
},
'requires': {
'dep': {},
+ },
},
},
}})
@@ -824,6 +810,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -833,6 +821,7 @@ Can't find all required implementations:
},
'requires': {
'sugar': {},
+ },
},
},
}})
@@ -842,7 +831,7 @@ Can't find all required implementations:
],
solver.solve(conn, context))
- conn.put(['implementation', impl], {
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -852,6 +841,7 @@ Can't find all required implementations:
},
'requires': {
'sugar': {'restrictions': [['0.80', '0.87']]},
+ },
},
},
}})
@@ -890,6 +880,8 @@ Can't find all required implementations:
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -899,6 +891,7 @@ Can't find all required implementations:
},
'requires': {
'sugar': {},
+ },
},
},
}})
diff --git a/tests/units/client/online_commands.py b/tests/units/client/online_commands.py
index 12c5570..692fa38 100755
--- a/tests/units/client/online_commands.py
+++ b/tests/units/client/online_commands.py
@@ -6,6 +6,7 @@ import json
import time
import shutil
import zipfile
+from cStringIO import StringIO
from os.path import exists
from __init__ import tests, src_root
@@ -13,6 +14,7 @@ from __init__ import tests, src_root
from sugar_network import client, db
from sugar_network.client import IPCClient, journal, clones, injector, commands
from sugar_network.toolkit import coroutine, http
+from sugar_network.toolkit.spec import Spec
from sugar_network.client.commands import ClientCommands
from sugar_network.resources.volume import Volume, Resource
from sugar_network.resources.user import User
@@ -71,6 +73,8 @@ class OnlineCommandsTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -78,24 +82,19 @@ class OnlineCommandsTest(tests.Test):
'exec': 'true',
},
},
- 'stability': 'stable',
- 'size': 0,
'extract': 'TestActivitry',
},
},
- })
- bundle = zipfile.ZipFile('bundle', 'w')
- bundle.writestr('TestActivitry/activity/activity.info', '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ]))
- bundle.close()
- ipc.request('PUT', ['implementation', impl, 'data'], file('bundle', 'rb').read())
+ 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivitry',
+ 'bundle_id = %s' % context,
+ 'exec = false',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license=Public Domain',
+ ]])),
+ }})
assert not exists('Activities/TestActivitry/activity/activity.info')
assert not exists('Activities/TestActivitry_1/activity/activity.info')
@@ -174,8 +173,27 @@ class OnlineCommandsTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
- 'requires': ['foo'],
})
+ self.node_volume['implementation'].update(impl1, {'data': {
+ 'blob': StringIO(self.zips(('TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license=GPLv3+',
+ ]))),
+ 'spec': {
+ '*-*': {
+ 'extract': 'TestActivity',
+ 'commands': {'activity': {'exec': 'true'}},
+ 'requires': {
+ 'dep1': {},
+ },
+ },
+ },
+ }})
impl2 = ipc.post(['implementation'], {
'context': context,
@@ -183,33 +201,27 @@ class OnlineCommandsTest(tests.Test):
'version': '2',
'stability': 'stable',
'notes': '',
- 'requires': ['bar'],
+ })
+ self.node_volume['implementation'].update(impl2, {'data': {
+ 'blob': StringIO(self.zips(('TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 2',
+ 'license=GPLv3+',
+ ]))),
'spec': {
'*-*': {
- 'commands': {
- 'activity': {
- 'exec': 'true',
- },
+ 'extract': 'TestActivity',
+ 'commands': {'activity': {'exec': 'true'}},
+ 'requires': {
+ 'dep2': {},
},
- 'stability': 'stable',
- 'size': 0,
- 'extract': 'TestActivitry',
- 'requires': {'dep': {}},
},
},
- })
- bundle = zipfile.ZipFile('bundle', 'w')
- bundle.writestr('TestActivitry/activity/activity.info', '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ]))
- bundle.close()
- ipc.request('PUT', ['implementation', impl2, 'data'], file('bundle', 'rb').read())
+ }})
impl3 = ipc.post(['implementation'], {
'context': context,
@@ -217,21 +229,57 @@ class OnlineCommandsTest(tests.Test):
'version': '3',
'stability': 'developer',
'notes': '',
- 'requires': ['bar'],
})
+ self.node_volume['implementation'].update(impl3, {'data': {
+ 'blob': StringIO(self.zips(('TestActivity/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivity',
+ 'bundle_id = %s' % context,
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 3',
+ 'license=GPLv3+',
+ ]))),
+ 'spec': {
+ '*-*': {
+ 'extract': 'TestActivity',
+ 'commands': {'activity': {'exec': 'true'}},
+ 'requires': {
+ 'dep3': {},
+ },
+ },
+ },
+ }})
- assert not exists('Activities/TestActivitry/activity/activity.info')
- self.assertEqual(
- {'clone': 0, 'type': ['activity']},
- ipc.get(['context', context], reply=['clone']))
+ ipc.put(['context', context], 2, cmd='clone', nodeps=1, requires='dep4')
+ coroutine.sleep(.1)
+ self.assertEqual({'clone': 0}, ipc.get(['context', context], reply=['clone']))
+ assert not exists('Activities/TestActivity/activity/activity.info')
- ipc.put(['context', context], 2, cmd='clone', nodeps=1, stability='stable', requires='bar')
- coroutine.sleep(.5)
+ ipc.put(['context', context], 2, cmd='clone', nodeps=1)
+ coroutine.sleep(.1)
+ self.assertEqual({'clone': 2}, ipc.get(['context', context], reply=['clone']))
+ self.assertEqual('2', Spec('Activities/TestActivity/activity/activity.info')['version'])
- assert exists('Activities/TestActivitry/activity/activity.info')
- self.assertEqual(
- {'clone': 2},
- ipc.get(['context', context], reply=['clone']))
+ ipc.put(['context', context], 0, cmd='clone')
+ coroutine.sleep(.1)
+ self.assertEqual({'clone': 0}, ipc.get(['context', context], reply=['clone']))
+ assert not exists('Activities/TestActivity/activity/activity.info')
+
+ ipc.put(['context', context], 2, cmd='clone', nodeps=1, stability='developer')
+ coroutine.sleep(.1)
+ self.assertEqual({'clone': 2}, ipc.get(['context', context], reply=['clone']))
+ self.assertEqual('3', Spec('Activities/TestActivity/activity/activity.info')['version'])
+
+ ipc.put(['context', context], 0, cmd='clone')
+ coroutine.sleep(.1)
+ self.assertEqual({'clone': 0}, ipc.get(['context', context], reply=['clone']))
+ assert not exists('Activities/TestActivity/activity/activity.info')
+
+ ipc.put(['context', context], 2, cmd='clone', nodeps=1, requires='dep1')
+ coroutine.sleep(.1)
+ self.assertEqual({'clone': 2}, ipc.get(['context', context], reply=['clone']))
+ self.assertEqual('1', Spec('Activities/TestActivity/activity/activity.info')['version'])
def test_clone_Content(self):
self.start_online_client()
@@ -528,14 +576,18 @@ class OnlineCommandsTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
- 'spec': {'*-*': {}},
})
+ self.node_volume['implementation'].update(impl1, {'data': {
+ 'spec': {'*-*': {}},
+ }})
impl2 = ipc.post(['implementation'], {
'context': context,
'license': 'GPLv3+',
'version': '2',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl2, {'data': {
'spec': {'*-*': {
'requires': {
'dep1': {},
@@ -544,7 +596,7 @@ class OnlineCommandsTest(tests.Test):
'dep4': {'restrictions': [['3', None]]},
},
}},
- })
+ }})
self.assertEqual({
'name': 'title',
@@ -554,6 +606,8 @@ class OnlineCommandsTest(tests.Test):
'arch': '*-*',
'stability': 'stable',
'guid': impl1,
+ 'unpack_size': None,
+ 'blob_size': None,
},
{
'version': '2',
@@ -566,6 +620,8 @@ class OnlineCommandsTest(tests.Test):
'dep3': {'restrictions': [[None, '2']]},
'dep4': {'restrictions': [['3', None]]},
},
+ 'unpack_size': None,
+ 'blob_size': None,
},
],
},
@@ -587,8 +643,10 @@ class OnlineCommandsTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
- 'spec': {'*-*': {}},
})
+ self.node_volume['implementation'].update(impl, {'data': {
+ 'spec': {'*-*': {}},
+ }})
artifact = ipc.post(['artifact'], {
'type': 'instance',
'context': 'context',
@@ -628,7 +686,14 @@ class OnlineCommandsTest(tests.Test):
self.assertEqual({
'name': 'title',
- 'implementations': [{'stability': 'stable', 'guid': impl, 'arch': '*-*', 'version': '1'}],
+ 'implementations': [{
+ 'stability': 'stable',
+ 'guid': impl,
+ 'arch': '*-*',
+ 'version': '1',
+ 'unpack_size': None,
+ 'blob_size': None,
+ }],
},
ipc.get(['context', context], cmd='feed'))
self.assertEqual({
@@ -638,7 +703,14 @@ class OnlineCommandsTest(tests.Test):
ipc.get(['context', context], cmd='feed', layer='foo'))
self.assertEqual({
'name': 'title',
- 'implementations': [{'stability': 'stable', 'guid': impl, 'arch': '*-*', 'version': '1'}],
+ 'implementations': [{
+ 'stability': 'stable',
+ 'guid': impl,
+ 'arch': '*-*',
+ 'version': '1',
+ 'unpack_size': None,
+ 'blob_size': None,
+ }],
},
ipc.get(['context', context], cmd='feed', layer='public'))
@@ -686,7 +758,14 @@ class OnlineCommandsTest(tests.Test):
ipc.get(['context', context], cmd='feed', layer='foo'))
self.assertEqual({
'name': 'title',
- 'implementations': [{'stability': 'stable', 'guid': impl, 'arch': '*-*', 'version': '1'}],
+ 'implementations': [{
+ 'stability': 'stable',
+ 'guid': impl,
+ 'arch': '*-*',
+ 'version': '1',
+ 'unpack_size': None,
+ 'blob_size': None,
+ }],
},
ipc.get(['context', context], cmd='feed', layer='public'))
@@ -706,8 +785,10 @@ class OnlineCommandsTest(tests.Test):
'version': '2',
'stability': 'stable',
'notes': '',
- 'spec': {'*-*': {}},
})
+ self.node_volume['implementation'].update(impl, {'data': {
+ 'spec': {'*-*': {}},
+ }})
self.assertEqual({
'name': 'title',
@@ -717,6 +798,8 @@ class OnlineCommandsTest(tests.Test):
'arch': '*-*',
'stability': 'stable',
'guid': impl,
+ 'unpack_size': None,
+ 'blob_size': None,
},
],
},
@@ -775,8 +858,10 @@ class OnlineCommandsTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
- 'spec': {'*-*': {}},
})
+ self.node_volume['implementation'].update(impl1, {'data': {
+ 'spec': {'*-*': {}},
+ }})
coroutine.sleep(.5)
assert injector._mtime > mtime
@@ -789,6 +874,8 @@ class OnlineCommandsTest(tests.Test):
'version': '2',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl2, {'data': {
'spec': {'*-*': {
'requires': {
'dep1': {},
@@ -797,7 +884,7 @@ class OnlineCommandsTest(tests.Test):
'dep4': {'restrictions': [['3', None]]},
},
}},
- })
+ }})
assert injector._mtime > mtime
def test_ContentDisposition(self):
@@ -984,6 +1071,8 @@ class OnlineCommandsTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
+ })
+ self.node_volume['implementation'].update(impl, {'data': {
'spec': {
'*-*': {
'commands': {
@@ -996,19 +1085,17 @@ class OnlineCommandsTest(tests.Test):
'extract': 'TestActivitry',
},
},
- })
- bundle = zipfile.ZipFile('bundle', 'w')
- bundle.writestr('TestActivitry/activity/activity.info', '\n'.join([
- '[Activity]',
- 'name = TestActivitry',
- 'bundle_id = %s' % context1,
- 'exec = false',
- 'icon = icon',
- 'activity_version = 1',
- 'license=Public Domain',
- ]))
- bundle.close()
- ipc.request('PUT', ['implementation', impl, 'data'], file('bundle', 'rb').read())
+ 'blob': StringIO(self.zips(['TestActivitry/activity/activity.info', [
+ '[Activity]',
+ 'name = TestActivitry',
+ 'bundle_id = %s' % context1,
+ 'exec = false',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license=Public Domain',
+ ]])),
+
+ }})
trigger = self.wait_for_events(ipc, event='update', document='context', guid=context1)
ipc.put(['context', context1], 2, cmd='clone')
diff --git a/tests/units/node/node.py b/tests/units/node/node.py
index 5e9eb33..a1bb46b 100755
--- a/tests/units/node/node.py
+++ b/tests/units/node/node.py
@@ -5,6 +5,7 @@ import os
import time
import json
from email.utils import formatdate, parsedate
+from cStringIO import StringIO
from os.path import exists
from __init__ import tests
@@ -432,12 +433,125 @@ class NodeTest(tests.Test):
'version': '1',
'stability': 'stable',
'notes': '',
- 'requires': ['foo', 'bar'],
})
- blob = self.zips(('topdir/probe', 'probe'))
- client.request('PUT', ['implementation', impl, 'data'], blob)
+ blob1 = self.zips(('topdir/probe', 'probe1'))
+ volume['implementation'].update(impl, {'data': {
+ 'blob': StringIO(blob1),
+ 'spec': {
+ '*-*': {
+ 'requires': {
+ 'dep1': {},
+ },
+ },
+ },
+ }})
+ impl = client.post(['implementation'], {
+ 'context': context,
+ 'license': 'GPLv3+',
+ 'version': '2',
+ 'stability': 'stable',
+ 'notes': '',
+ })
+ blob2 = self.zips(('topdir/probe', 'probe2'))
+ volume['implementation'].update(impl, {'data': {
+ 'blob': StringIO(blob2),
+ 'spec': {
+ '*-*': {
+ 'requires': {
+ 'dep2': {'restrictions': [[None, '2']]},
+ 'dep3': {},
+ },
+ },
+ },
+ }})
+ impl = client.post(['implementation'], {
+ 'context': context,
+ 'license': 'GPLv3+',
+ 'version': '3',
+ 'stability': 'stable',
+ 'notes': '',
+ })
+ blob3 = self.zips(('topdir/probe', 'probe3'))
+ volume['implementation'].update(impl, {'data': {
+ 'blob': StringIO(blob3),
+ 'spec': {
+ '*-*': {
+ 'requires': {
+ 'dep2': {'restrictions': [['2', None]]},
+ },
+ },
+ },
+ }})
+ impl = client.post(['implementation'], {
+ 'context': context,
+ 'license': 'GPLv3+',
+ 'version': '4',
+ 'stability': 'developer',
+ 'notes': '',
+ })
+ blob4 = self.zips(('topdir/probe', 'probe4'))
+ volume['implementation'].update(impl, {'data': {
+ 'blob': StringIO(blob4),
+ 'spec': {
+ '*-*': {
+ 'requires': {},
+ },
+ },
+ }})
+
+ self.assertEqual(blob3, client.get(['context', context], cmd='clone'))
+ self.assertEqual(blob4, client.get(['context', context], cmd='clone', stability='developer'))
+ self.assertEqual(blob1, client.get(['context', context], cmd='clone', version='1'))
+
+ self.assertEqual(blob1, client.get(['context', context], cmd='clone', requires='dep1'))
+ self.assertEqual(blob3, client.get(['context', context], cmd='clone', requires='dep2'))
+ self.assertEqual(blob2, client.get(['context', context], cmd='clone', requires='dep2=1'))
+ self.assertEqual(blob3, client.get(['context', context], cmd='clone', requires='dep2=2'))
+ self.assertEqual(blob2, client.get(['context', context], cmd='clone', requires='dep3'))
+
+ self.assertRaises(http.NotFound, client.get, ['context', context], cmd='clone', requires='dep4')
+ self.assertRaises(http.NotFound, client.get, ['context', context], cmd='clone', stability='foo')
+
+ def test_release(self):
+ volume = self.start_master()
+ conn = Client()
+
+ conn.post(['context'], {
+ 'guid': 'bundle_id',
+ 'type': 'activity',
+ 'title': 'title',
+ 'summary': 'summary',
+ 'description': 'description',
+ })
+ activity_info = '\n'.join([
+ '[Activity]',
+ 'name = TestActivitry',
+ 'bundle_id = bundle_id',
+ 'exec = true',
+ 'icon = icon',
+ 'activity_version = 1',
+ 'license = Public Domain',
+ 'stability = developer',
+ 'requires = sugar>=0.88; dep'
+ ])
+ bundle = self.zips(('topdir/activity/activity.info', activity_info))
+ guid = json.load(conn.request('POST', ['implementation'], bundle, params={'cmd': 'release'}).raw)
+
+ impl = volume['implementation'].get(guid)
+ self.assertEqual('bundle_id', impl['context'])
+ self.assertEqual('1', impl['version'])
+ self.assertEqual('developer', impl['stability'])
+ self.assertEqual(['Public Domain'], impl['license'])
+ self.assertEqual('developer', impl['stability'])
+
+ data = impl.meta('data')
+ self.assertEqual('application/vnd.olpc-sugar', data['mime_type'])
+ self.assertEqual(len(bundle), data['blob_size'])
+ self.assertEqual(len(activity_info), data.get('unpack_size'))
+
+
+
- self.assertEqual(blob, client.get(['context', context], cmd='clone', version='1', stability='stable', requires=['foo', 'bar']))
def call(cp, principal=None, content=None, **kwargs):
diff --git a/tests/units/node/volume.py b/tests/units/node/volume.py
index 85ec1e2..15772e1 100755
--- a/tests/units/node/volume.py
+++ b/tests/units/node/volume.py
@@ -352,7 +352,6 @@ class VolumeTest(tests.Test):
context = call(cp, method='POST', document='context', principal='principal', content={
'guid': 'context',
- 'implement': 'guid',
'type': 'package',
'title': 'title',
'summary': 'summary',
diff --git a/tests/units/resources/implementation.py b/tests/units/resources/implementation.py
index 6ff73cb..176051c 100755
--- a/tests/units/resources/implementation.py
+++ b/tests/units/resources/implementation.py
@@ -48,7 +48,7 @@ class ImplementationTest(tests.Test):
_encode_version('1-'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''000')),
- _encode_version('1-post'))
+ _encode_version('1-r'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''3''001')),
@@ -58,112 +58,14 @@ class ImplementationTest(tests.Test):
_encode_version('1-rc2'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''003')),
- _encode_version('1-post3'))
+ _encode_version('1-r3'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''000')),
- _encode_version('1-post-2-3'))
+ _encode_version('1-r-2-3'))
self.assertEqual(
xapian.sortable_serialise(eval('1''0000''0000''6''001')),
- _encode_version('1-post1.2-3'))
-
- def test_ActivitityFiles(self):
- self.start_online_client()
- client = IPCClient()
-
- context = client.post(['context'], {
- 'type': 'content',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = client.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- client.request('PUT', ['implementation', impl, 'data'], 'blob', {'Content-Type': 'image/png'})
- self.assertEqual('image/png', self.node_volume['implementation'].get(impl).meta('data')['mime_type'])
-
- client.put(['context', context, 'type'], 'activity')
- client.request('PUT', ['implementation', impl, 'data'], self.zips(('topdir/probe', 'probe')))
-
- data = self.node_volume['implementation'].get(impl).meta('data')
- self.assertEqual('application/vnd.olpc-sugar', data['mime_type'])
- self.assertNotEqual(5, data['blob_size'])
- self.assertEqual(5, data.get('unpack_size'))
-
- def test_ActivityUrls(self):
- bundle = self.zips(('topdir/probe', 'probe'))
- unpack_size = len('probe')
-
- class Files(db.CommandsProcessor):
-
- @route('GET', '/bundle')
- def bundle(self, request, response):
- return bundle
-
- self.start_online_client()
- client = IPCClient()
- files_server = coroutine.WSGIServer(('127.0.0.1', 9999), Router(Files()))
- coroutine.spawn(files_server.serve_forever)
- coroutine.dispatch()
-
- context = client.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = client.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- client.put(['implementation', impl, 'data'], {'url': 'http://127.0.0.1:9999/bundle'})
-
- data = self.node_volume['implementation'].get(impl).meta('data')
- self.assertEqual('application/vnd.olpc-sugar', data['mime_type'])
- self.assertEqual(len(bundle), data['blob_size'])
- self.assertEqual(unpack_size, data.get('unpack_size'))
- self.assertEqual('http://127.0.0.1:9999/bundle', data['url'])
- assert 'blob' not in data
-
- def test_ActivityASLOUrls(self):
- implementation._ASLO_PATH = '.'
- bundle = self.zips(('topdir/probe', 'probe'))
- with file('bundle', 'w') as f:
- f.write(bundle)
- unpack_size = len('probe')
-
- self.start_online_client()
- client = IPCClient()
-
- context = client.post(['context'], {
- 'type': 'activity',
- 'title': 'title',
- 'summary': 'summary',
- 'description': 'description',
- })
- impl = client.post(['implementation'], {
- 'context': context,
- 'license': 'GPLv3+',
- 'version': '1',
- 'stability': 'stable',
- 'notes': '',
- })
- client.put(['implementation', impl, 'data'], {'url': 'http://download.sugarlabs.org/activities/bundle'})
-
- data = self.node_volume['implementation'].get(impl).meta('data')
- self.assertEqual('application/vnd.olpc-sugar', data['mime_type'])
- self.assertEqual(len(bundle), data['blob_size'])
- self.assertEqual(unpack_size, data.get('unpack_size'))
- self.assertEqual('http://download.sugarlabs.org/activities/bundle', data['url'])
- assert 'blob' not in data
+ _encode_version('1-r1.2-3'))
def test_WrongAuthor(self):
self.start_online_client()
diff --git a/tests/units/toolkit/spec.py b/tests/units/toolkit/spec.py
index 1cdf36e..e34b6ec 100755
--- a/tests/units/toolkit/spec.py
+++ b/tests/units/toolkit/spec.py
@@ -10,7 +10,7 @@ from sugar_network.toolkit import spec
class SpecTest(tests.Test):
- def test_Dependency(self):
+ def test_Dependency_versions_range(self):
self.assertEqual(
[],
[i for i in spec._Dependency().versions_range()])
@@ -18,6 +18,12 @@ class SpecTest(tests.Test):
[],
[i for i in spec._Dependency({'restrictions': []}).versions_range()])
self.assertEqual(
+ [],
+ [i for i in spec._Dependency({'restrictions': [(None, '2')]}).versions_range()])
+ self.assertEqual(
+ [],
+ [i for i in spec._Dependency({'restrictions': [('1', None)]}).versions_range()])
+ self.assertEqual(
['1'],
[i for i in spec._Dependency({'restrictions': [('1', '2')]}).versions_range()])
self.assertEqual(
@@ -36,7 +42,7 @@ class SpecTest(tests.Test):
def test_parse_requires(self):
self.assertEqual(
{'a': {}, 'b': {}, 'c': {}},
- spec._parse_requires('a; b; c'))
+ spec.parse_requires('a; b; c'))
self.assertEqual(
{
@@ -44,8 +50,10 @@ class SpecTest(tests.Test):
'b': {'restrictions': [('1.2', '1.3')]},
'c': {'restrictions': [('2.2', None)]},
'd': {'restrictions': [(None, '3')]},
+ 'e': {'restrictions': [('4.1', None)]},
+ 'f': {'restrictions': [(None, '5.1')]},
},
- spec._parse_requires('a = 1; b=1.2; c>= 2.2; d <3-3'))
+ spec.parse_requires('a = 1; b=1.2; c>= 2.2; d <3-3; e > 4; f<=5'))
self.assertEqual(
{
@@ -53,7 +61,7 @@ class SpecTest(tests.Test):
'b': {},
'c': {'importance': 'recommended', 'restrictions': [(None, '1')]},
},
- spec._parse_requires('[a]; b; [c<1]'))
+ spec.parse_requires('[a]; b; [c<1]'))
def test_parse_bindings(self):
self.assertEqual(
@@ -168,6 +176,39 @@ class SpecTest(tests.Test):
assert pv('2-r999') < pv('3-pre1')
+ def test_ensure_requires(self):
+ assert spec.ensure_requires(spec.parse_requires(''), spec.parse_requires(''))
+
+ assert not spec.ensure_requires(spec.parse_requires(''), spec.parse_requires('d1'))
+ assert spec.ensure_requires(spec.parse_requires('d1'), spec.parse_requires(''))
+ assert spec.ensure_requires(spec.parse_requires('d1'), spec.parse_requires('d1'))
+
+ assert not spec.ensure_requires(spec.parse_requires(''), spec.parse_requires('d1; d2'))
+ assert spec.ensure_requires(spec.parse_requires('d1; d2'), spec.parse_requires(''))
+ assert not spec.ensure_requires(spec.parse_requires('d1'), spec.parse_requires('d1; d2'))
+ assert spec.ensure_requires(spec.parse_requires('d1; d2'), spec.parse_requires('d1'))
+ assert spec.ensure_requires(spec.parse_requires('d1; d2'), spec.parse_requires('d1; d2'))
+
+ assert spec.ensure_requires(spec.parse_requires('d1'), spec.parse_requires('d1 < 1'))
+ assert spec.ensure_requires(spec.parse_requires('d1 < 1'), spec.parse_requires('d1'))
+ assert spec.ensure_requires(spec.parse_requires('d1 < 1'), spec.parse_requires('d1 < 2'))
+ assert spec.ensure_requires(spec.parse_requires('d1 < 2'), spec.parse_requires('d1 < 1'))
+
+ assert spec.ensure_requires(spec.parse_requires('d1'), spec.parse_requires('d1 > 1'))
+ assert spec.ensure_requires(spec.parse_requires('d1 > 1'), spec.parse_requires('d1'))
+ assert spec.ensure_requires(spec.parse_requires('d1 > 1'), spec.parse_requires('d1 > 2'))
+ assert spec.ensure_requires(spec.parse_requires('d1 > 2'), spec.parse_requires('d1 > 1'))
+
+ assert spec.ensure_requires(spec.parse_requires('d1'), spec.parse_requires('d1 > 1; d1 < 2'))
+ assert spec.ensure_requires(spec.parse_requires('d1 > 1; d1 < 2'), spec.parse_requires('d1'))
+ assert spec.ensure_requires(spec.parse_requires('d1 > 1; d1 < 2'), spec.parse_requires('d1 > 0; d1 < 3'))
+ assert spec.ensure_requires(spec.parse_requires('d1 > 0; d1 < 3'), spec.parse_requires('d1 > 1; d1 < 2'))
+
+ assert spec.ensure_requires(spec.parse_requires('d1 > 1; d1 <= 2'), spec.parse_requires('d1 >= 2; d1 < 3'))
+ assert spec.ensure_requires(spec.parse_requires('d1 >= 1; d1 < 2'), spec.parse_requires('d1 > 0; d1 <= 1'))
+ assert not spec.ensure_requires(spec.parse_requires('d1 > 1; d1 < 2'), spec.parse_requires('d1 > 2; d1 < 3'))
+ assert not spec.ensure_requires(spec.parse_requires('d1 > 1; d1 < 2'), spec.parse_requires('d1 > 0; d1 < 1'))
+
if __name__ == '__main__':
tests.main()