OLD | NEW |
1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package dm | 5 package dm |
6 | 6 |
7 import ( | 7 import ( |
8 "fmt" | 8 "fmt" |
9 "strconv" | 9 "strconv" |
10 "strings" | 10 "strings" |
11 | 11 |
12 "github.com/luci/gae/service/datastore" | 12 "github.com/luci/gae/service/datastore" |
13 ) | 13 ) |
14 | 14 |
15 const flipMask uint32 = 0xFFFFFFFF | 15 const flipMask uint32 = 0xFFFFFFFF |
16 | 16 |
17 var _ datastore.PropertyConverter = (*Attempt_ID)(nil) | 17 var _ datastore.PropertyConverter = (*Attempt_ID)(nil) |
18 var _ datastore.PropertyConverter = (*Execution_ID)(nil) | |
19 | 18 |
20 // NewQuestID is a shorthand to New a new *Quest_ID | 19 // NewQuestID is a shorthand to New a new *Quest_ID |
21 func NewQuestID(qst string) *Quest_ID { | 20 func NewQuestID(qst string) *Quest_ID { |
22 return &Quest_ID{qst} | 21 return &Quest_ID{qst} |
23 } | 22 } |
24 | 23 |
25 // NewAttemptID is a shorthand to New a new *Attempt_ID | 24 // NewAttemptID is a shorthand to New a new *Attempt_ID |
26 func NewAttemptID(qst string, aid uint32) *Attempt_ID { | 25 func NewAttemptID(qst string, aid uint32) *Attempt_ID { |
27 return &Attempt_ID{qst, aid} | 26 return &Attempt_ID{qst, aid} |
28 } | 27 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 an, err := strconv.ParseUint(toks[1], 16, 32) | 67 an, err := strconv.ParseUint(toks[1], 16, 32) |
69 if err != nil { | 68 if err != nil { |
70 return err | 69 return err |
71 } | 70 } |
72 | 71 |
73 a.Quest = toks[0] | 72 a.Quest = toks[0] |
74 a.Id = flipMask ^ uint32(an) | 73 a.Id = flipMask ^ uint32(an) |
75 return nil | 74 return nil |
76 } | 75 } |
77 | 76 |
78 // ToProperty implements datastore.PropertyConverter for the purpose of | |
79 // embedding this Execution_ID as the ID of a luci/gae compatible datastore | |
80 // object. The numerical id field is stored as an inverted, hex-encoded string, | |
81 // so that Execution_ID{"quest", 1, 2} would encode as "quest|fffffffe|fffffffd"
. | |
82 // This is done so that the __key__ ordering in the dm application prefers to | |
83 // order the most recent executions first. | |
84 // | |
85 // The go representation will always have the normal non-flipped numerical ids. | |
86 func (e *Execution_ID) ToProperty() (datastore.Property, error) { | |
87 return datastore.MkPropertyNI(e.DMEncoded()), nil | |
88 } | |
89 | |
90 // FromProperty implements datastore.PropertyConverter | |
91 func (e *Execution_ID) FromProperty(p datastore.Property) error { | |
92 if p.Type() != datastore.PTString { | |
93 return fmt.Errorf("wrong type for property: %s", p.Type()) | |
94 } | |
95 return e.SetDMEncoded(p.Value().(string)) | |
96 } | |
97 | |
98 // DMEncoded returns the encoded inverted string id for this Execution. Numeric | |
99 // values are inverted if flip is true. | |
100 func (e *Execution_ID) DMEncoded() string { | |
101 return fmt.Sprintf("%s|%08x|%08x", e.Quest, flipMask^e.Attempt, flipMask
^e.Id) | |
102 } | |
103 | |
104 // SetDMEncoded decodes val into this Execution_ID, returning an error if | |
105 // there's a problem. Numeric values are inverted if flip is true. | |
106 func (e *Execution_ID) SetDMEncoded(val string) error { | |
107 toks := strings.SplitN(val, "|", 3) | |
108 if len(toks) != 3 { | |
109 return fmt.Errorf("unable to parse Execution id: %q", val) | |
110 } | |
111 an, err := strconv.ParseUint(toks[1], 16, 32) | |
112 if err != nil { | |
113 return err | |
114 } | |
115 en, err := strconv.ParseUint(toks[2], 16, 32) | |
116 if err != nil { | |
117 return err | |
118 } | |
119 | |
120 e.Quest = toks[0] | |
121 e.Attempt = flipMask ^ uint32(an) | |
122 e.Id = flipMask ^ uint32(en) | |
123 return nil | |
124 } | |
125 | |
126 // GetQuest gets the specified quest from GraphData, if it's already there. If | 77 // GetQuest gets the specified quest from GraphData, if it's already there. If |
127 // it's not, then a new Quest will be created, added, and returned. | 78 // it's not, then a new Quest will be created, added, and returned. |
128 // | 79 // |
129 // If the Quests map is uninitialized, this will initialize it. | 80 // If the Quests map is uninitialized, this will initialize it. |
130 func (g *GraphData) GetQuest(qid string) (*Quest, bool) { | 81 func (g *GraphData) GetQuest(qid string) (*Quest, bool) { |
131 cur, ok := g.Quests[qid] | 82 cur, ok := g.Quests[qid] |
132 if !ok { | 83 if !ok { |
133 cur = &Quest{ | 84 cur = &Quest{ |
134 Id: NewQuestID(qid), | 85 Id: NewQuestID(qid), |
135 Attempts: map[uint32]*Attempt{}, | 86 Attempts: map[uint32]*Attempt{}, |
136 } | 87 } |
137 if g.Quests == nil { | 88 if g.Quests == nil { |
138 g.Quests = map[string]*Quest{} | 89 g.Quests = map[string]*Quest{} |
139 } | 90 } |
140 g.Quests[qid] = cur | 91 g.Quests[qid] = cur |
141 } | 92 } |
142 return cur, ok | 93 return cur, ok |
143 } | 94 } |
144 | 95 |
145 // NewQuestDesc is a shorthand method for building a new *Quest_Desc. | 96 // NewQuestDesc is a shorthand method for building a new *Quest_Desc. |
146 func NewQuestDesc(cfg string, js string) *Quest_Desc { | 97 func NewQuestDesc(cfg string, js string, meta *Quest_Desc_Meta) *Quest_Desc { |
147 » return &Quest_Desc{cfg, js} | 98 » return &Quest_Desc{cfg, js, meta} |
148 } | 99 } |
149 | 100 |
150 // NewTemplateSpec is a shorthand method for building a new *Quest_TemplateSpec. | 101 // NewTemplateSpec is a shorthand method for building a new *Quest_TemplateSpec. |
151 func NewTemplateSpec(project, ref, version, name string) *Quest_TemplateSpec { | 102 func NewTemplateSpec(project, ref, version, name string) *Quest_TemplateSpec { |
152 return &Quest_TemplateSpec{project, ref, version, name} | 103 return &Quest_TemplateSpec{project, ref, version, name} |
153 } | 104 } |
154 | 105 |
155 // Equals returns true iff this Quest_TemplateSpec matches all of the fields of | 106 // Equals returns true iff this Quest_TemplateSpec matches all of the fields of |
156 // the `o` Quest_TemplateSpec. | 107 // the `o` Quest_TemplateSpec. |
157 func (t *Quest_TemplateSpec) Equals(o *Quest_TemplateSpec) bool { | 108 func (t *Quest_TemplateSpec) Equals(o *Quest_TemplateSpec) bool { |
158 return (t.Project == o.Project && t.Ref == o.Ref && t.Version == o.Versi
on && | 109 return (t.Project == o.Project && t.Ref == o.Ref && t.Version == o.Versi
on && |
159 t.Name == o.Name) | 110 t.Name == o.Name) |
160 } | 111 } |
OLD | NEW |