Merge lp:~niemeyer/pyjuju/go-initial-formula-meta into lp:pyjuju/go

Proposed by Gustavo Niemeyer
Status: Merged
Approved by: Kapil Thangavelu
Approved revision: 7
Merged at revision: 4
Proposed branch: lp:~niemeyer/pyjuju/go-initial-formula-meta
Merge into: lp:pyjuju/go
Prerequisite: lp:~niemeyer/pyjuju/go-iface-schema
Diff against target: 193 lines (+140/-5)
2 files modified
formula/formula.go (+64/-5)
formula/formula_test.go (+76/-0)
To merge this branch: bzr merge lp:~niemeyer/pyjuju/go-initial-formula-meta
Reviewer Review Type Date Requested Status
Kapil Thangavelu (community) Approve
William Reade (community) Approve
Review via email: mp+73138@code.launchpad.net

Description of the change

Initial (and incomplete) metadata.yaml parsing.

Stacks on the unmerged go-iface-schema branch.

To post a comment you must log in.
Revision history for this message
William Reade (fwereade) wrote :

[0]

+ "peers": schema.Map(schema.String(), ifaceExpander(1)),

Is this right? It matches the Python, but the docs seem to suggest it should be ifaceExpander(nil):

http://bazaar.launchpad.net/~ensemble/ensemble/trunk/view/head:/docs/source/formula.rst#L69

Otherwise, +1.

review: Approve
Revision history for this message
Kapil Thangavelu (hazmat) wrote :

Looks good.

[0] it definitely make sense for the default limit on a peer rel to be one. the docs should be updated.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'formula/formula.go'
2--- formula/formula.go 2011-08-27 14:47:24 +0000
3+++ formula/formula.go 2011-08-27 14:47:24 +0000
4@@ -2,7 +2,9 @@
5
6 import (
7 "fmt"
8+ "io/ioutil"
9 "launchpad.net/ensemble/go/schema"
10+ "launchpad.net/goyaml"
11 "os"
12 "strconv"
13 "strings"
14@@ -32,11 +34,48 @@
15 return
16 }
17
18-var ifaceSchema = schema.FieldMap(schema.Fields{
19- "interface": schema.String(),
20- "limit": schema.OneOf(schema.Const(nil), schema.Int()),
21- "optional": schema.Bool(),
22-}, nil)
23+type Meta struct {
24+ Name string
25+ Revision int
26+ Summary string
27+ Description string
28+}
29+
30+// ReadMeta reads a metadata.yaml file and returns its representation.
31+func ReadMeta(path string) (meta *Meta, err os.Error) {
32+ data, err := ioutil.ReadFile(path)
33+ if err != nil {
34+ return
35+ }
36+ meta, err = ParseMeta(data)
37+ if err != nil {
38+ err = os.NewError(fmt.Sprintf("%s: %s", path, err))
39+ }
40+ return
41+}
42+
43+// ParseMeta parses the data of a metadata.yaml file and returns
44+// its representation.
45+func ParseMeta(data []byte) (meta *Meta, err os.Error) {
46+ raw := make(map[interface{}]interface{})
47+ err = goyaml.Unmarshal(data, raw)
48+ if err != nil {
49+ return
50+ }
51+ v, err := formulaSchema.Coerce(raw, nil)
52+ if err != nil {
53+ return
54+ }
55+ m := v.(schema.M)
56+ meta = &Meta{}
57+ meta.Name = m["name"].(string)
58+ // Schema decodes as int64, but the int range should be good
59+ // enough for revisions.
60+ meta.Revision = int(m["revision"].(int64))
61+ meta.Summary = m["summary"].(string)
62+ meta.Description = m["description"].(string)
63+ return
64+}
65
66 // Schema coercer that expands the interface shorthand notation.
67 // A consistent format is easier to work with than considering the
68@@ -99,3 +138,23 @@
69 }
70 return ifaceSchema.Coerce(m, path)
71 }
72+
73+var ifaceSchema = schema.FieldMap(schema.Fields{
74+ "interface": schema.String(),
75+ "limit": schema.OneOf(schema.Const(nil), schema.Int()),
76+ "optional": schema.Bool(),
77+}, nil)
78+
79+var formulaSchema = schema.FieldMap(
80+ schema.Fields{
81+ "ensemble": schema.Const("formula"),
82+ "name": schema.String(),
83+ "revision": schema.Int(),
84+ "summary": schema.String(),
85+ "description": schema.String(),
86+ "peers": schema.Map(schema.String(), ifaceExpander(1)),
87+ "provides": schema.Map(schema.String(), ifaceExpander(nil)),
88+ "requires": schema.Map(schema.String(), ifaceExpander(1)),
89+ },
90+ schema.Optional{"provides", "requires", "peers"},
91+)
92
93=== modified file 'formula/formula_test.go'
94--- formula/formula_test.go 2011-08-27 14:47:24 +0000
95+++ formula/formula_test.go 2011-08-27 14:47:24 +0000
96@@ -1,10 +1,13 @@
97 package formula_test
98
99 import (
100+ "io/ioutil"
101 "testing"
102 . "launchpad.net/gocheck"
103 "launchpad.net/ensemble/go/formula"
104 "launchpad.net/ensemble/go/schema"
105+ "launchpad.net/goyaml"
106+ "path/filepath"
107 )
108
109 func Test(t *testing.T) {
110@@ -35,6 +38,57 @@
111 c.Assert(err, Matches, `Missing formula revision: "local:foo-x"`)
112 }
113
114+const dummyMeta = "testrepo/dummy/metadata.yaml"
115+
116+func (s *S) TestReadMeta(c *C) {
117+ meta, err := formula.ReadMeta(dummyMeta)
118+ c.Assert(err, IsNil)
119+ c.Assert(meta.Name, Equals, "dummy")
120+ c.Assert(meta.Revision, Equals, 1)
121+ c.Assert(meta.Summary, Equals, "That's a dummy formula.")
122+ c.Assert(meta.Description, Equals,
123+ "This is a longer description which\npotentially contains multiple lines.\n")
124+}
125+
126+func (s *S) TestParseMeta(c *C) {
127+ data, err := ioutil.ReadFile(dummyMeta)
128+ c.Assert(err, IsNil)
129+
130+ meta, err := formula.ParseMeta(data)
131+ c.Assert(err, IsNil)
132+ c.Assert(meta.Name, Equals, "dummy")
133+ c.Assert(meta.Revision, Equals, 1)
134+ c.Assert(meta.Summary, Equals, "That's a dummy formula.")
135+ c.Assert(meta.Description, Equals,
136+ "This is a longer description which\npotentially contains multiple lines.\n")
137+}
138+
139+func (s *S) TestMetaHeader(c *C) {
140+ yaml := ReadYaml(dummyMeta)
141+ yaml["ensemble"] = "foo"
142+ data := DumpYaml(yaml)
143+
144+ _, err := formula.ParseMeta(data)
145+ c.Assert(err, Matches, `ensemble: expected "formula", got "foo"`)
146+}
147+
148+func (s *S) TestMetaErrorWithPath(c *C) {
149+ yaml := ReadYaml(dummyMeta)
150+ yaml["ensemble"] = "foo"
151+ data := DumpYaml(yaml)
152+
153+ path := filepath.Join(c.MkDir(), "mymeta.yaml")
154+
155+ _, err := formula.ReadMeta(path)
156+ c.Assert(err, Matches, `.*/.*/mymeta\.yaml.*no such file.*`)
157+
158+ err = ioutil.WriteFile(path, data, 0644)
159+ c.Assert(err, IsNil)
160+
161+ _, err = formula.ReadMeta(path)
162+ c.Assert(err, Matches, `/.*/mymeta\.yaml: ensemble: expected "formula", got "foo"`)
163+}
164+
165 // Test rewriting of a given interface specification into long form.
166 //
167 // InterfaceExpander uses `coerce` to do one of two things:
168@@ -84,3 +138,25 @@
169 c.Assert(err, IsNil)
170 c.Assert(v, Equals, schema.M{"interface": "http", "limit": int64(1), "optional": false})
171 }
172+
173+
174+func ReadYaml(path string) map[interface{}]interface{} {
175+ data, err := ioutil.ReadFile(path)
176+ if err != nil {
177+ panic(err)
178+ }
179+ m := make(map[interface{}]interface{})
180+ err = goyaml.Unmarshal(data, m)
181+ if err != nil {
182+ panic(err)
183+ }
184+ return m
185+}
186+
187+func DumpYaml(v interface{}) []byte {
188+ data, err := goyaml.Marshal(v)
189+ if err != nil {
190+ panic(err)
191+ }
192+ return data
193+}

Subscribers

People subscribed via source and target branches