OLD | NEW |
1 // Copyright 2017 The LUCI Authors. All rights reserved. | 1 // Copyright 2017 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 wheel | 5 package wheel |
6 | 6 |
7 import ( | 7 import ( |
8 "fmt" | 8 "fmt" |
9 "os" | 9 "os" |
10 "path/filepath" | 10 "path/filepath" |
(...skipping 30 matching lines...) Expand all Loading... |
41 wn.ABITag, | 41 wn.ABITag, |
42 wn.PlatformTag, | 42 wn.PlatformTag, |
43 }...) | 43 }...) |
44 return strings.Join(parts, "-") + ".whl" | 44 return strings.Join(parts, "-") + ".whl" |
45 } | 45 } |
46 | 46 |
47 // ParseName parses a wheel Name from its filename. | 47 // ParseName parses a wheel Name from its filename. |
48 func ParseName(v string) (wn Name, err error) { | 48 func ParseName(v string) (wn Name, err error) { |
49 base := strings.TrimSuffix(v, ".whl") | 49 base := strings.TrimSuffix(v, ".whl") |
50 if len(base) == len(v) { | 50 if len(base) == len(v) { |
51 » » err = errors.Reason("missing .whl suffix").Err() | 51 » » err = errors.New("missing .whl suffix") |
52 return | 52 return |
53 } | 53 } |
54 | 54 |
55 skip := 0 | 55 skip := 0 |
56 switch parts := strings.Split(base, "-"); len(parts) { | 56 switch parts := strings.Split(base, "-"); len(parts) { |
57 case 6: | 57 case 6: |
58 // Extra part: build tag. | 58 // Extra part: build tag. |
59 wn.BuildTag = parts[2] | 59 wn.BuildTag = parts[2] |
60 skip = 1 | 60 skip = 1 |
61 fallthrough | 61 fallthrough |
62 | 62 |
63 case 5: | 63 case 5: |
64 wn.Distribution = parts[0] | 64 wn.Distribution = parts[0] |
65 wn.Version = parts[1] | 65 wn.Version = parts[1] |
66 wn.PythonTag = parts[2+skip] | 66 wn.PythonTag = parts[2+skip] |
67 wn.ABITag = parts[3+skip] | 67 wn.ABITag = parts[3+skip] |
68 wn.PlatformTag = parts[4+skip] | 68 wn.PlatformTag = parts[4+skip] |
69 | 69 |
70 default: | 70 default: |
71 » » err = errors.Reason("unknown number of segments (%(segments)d)")
. | 71 » » err = errors.Reason("unknown number of segments (%d)", len(parts
)).Err() |
72 » » » D("segments", len(parts)). | |
73 » » » Err() | |
74 return | 72 return |
75 } | 73 } |
76 return | 74 return |
77 } | 75 } |
78 | 76 |
79 // ScanDir identifies all wheel files in the immediate directory dir and | 77 // ScanDir identifies all wheel files in the immediate directory dir and |
80 // returns their parsed wheel names. | 78 // returns their parsed wheel names. |
81 func ScanDir(dir string) ([]Name, error) { | 79 func ScanDir(dir string) ([]Name, error) { |
82 globPattern := filepath.Join(dir, "*.whl") | 80 globPattern := filepath.Join(dir, "*.whl") |
83 matches, err := filepath.Glob(globPattern) | 81 matches, err := filepath.Glob(globPattern) |
84 if err != nil { | 82 if err != nil { |
85 » » return nil, errors.Annotate(err).Reason("failed to list wheel di
rectory: %(dir)s"). | 83 » » return nil, errors.Annotate(err, "failed to list wheel directory
: %s", dir). |
86 » » » D("dir", dir). | 84 » » » InternalReason("pattern(%s)", globPattern).Err() |
87 » » » D("pattern", globPattern). | |
88 » » » Err() | |
89 } | 85 } |
90 | 86 |
91 names := make([]Name, 0, len(matches)) | 87 names := make([]Name, 0, len(matches)) |
92 for _, match := range matches { | 88 for _, match := range matches { |
93 switch st, err := os.Stat(match); { | 89 switch st, err := os.Stat(match); { |
94 case err != nil: | 90 case err != nil: |
95 » » » return nil, errors.Annotate(err).Reason("failed to stat
wheel: %(path)s"). | 91 » » » return nil, errors.Annotate(err, "failed to stat wheel:
%s", match).Err() |
96 » » » » D("path", match). | |
97 » » » » Err() | |
98 | 92 |
99 case st.IsDir(): | 93 case st.IsDir(): |
100 // Ignore directories. | 94 // Ignore directories. |
101 continue | 95 continue |
102 | 96 |
103 default: | 97 default: |
104 // A ".whl" file. | 98 // A ".whl" file. |
105 name := filepath.Base(match) | 99 name := filepath.Base(match) |
106 wheelName, err := ParseName(name) | 100 wheelName, err := ParseName(name) |
107 if err != nil { | 101 if err != nil { |
108 » » » » return nil, errors.Annotate(err).Reason("failed
to parse wheel from: %(name)s"). | 102 » » » » return nil, errors.Annotate(err, "failed to pars
e wheel from: %s", name). |
109 » » » » » D("name", name). | 103 » » » » » InternalReason("dir(%s)", dir).Err() |
110 » » » » » D("dir", dir). | |
111 » » » » » Err() | |
112 } | 104 } |
113 names = append(names, wheelName) | 105 names = append(names, wheelName) |
114 } | 106 } |
115 } | 107 } |
116 return names, nil | 108 return names, nil |
117 } | 109 } |
118 | 110 |
119 // WriteRequirementsFile writes a valid "requirements.txt"-style pip | 111 // WriteRequirementsFile writes a valid "requirements.txt"-style pip |
120 // requirements file containing the supplied wheels. | 112 // requirements file containing the supplied wheels. |
121 // | 113 // |
122 // The generated requirements will request the exact wheel senver version (using | 114 // The generated requirements will request the exact wheel senver version (using |
123 // "=="). | 115 // "=="). |
124 func WriteRequirementsFile(path string, wheels []Name) (err error) { | 116 func WriteRequirementsFile(path string, wheels []Name) (err error) { |
125 fd, err := os.Create(path) | 117 fd, err := os.Create(path) |
126 if err != nil { | 118 if err != nil { |
127 » » return errors.Annotate(err).Reason("failed to create requirement
s file").Err() | 119 » » return errors.Annotate(err, "failed to create requirements file"
).Err() |
128 } | 120 } |
129 defer func() { | 121 defer func() { |
130 closeErr := fd.Close() | 122 closeErr := fd.Close() |
131 if closeErr != nil && err == nil { | 123 if closeErr != nil && err == nil { |
132 » » » err = errors.Annotate(closeErr).Reason("failed to Close"
).Err() | 124 » » » err = errors.Annotate(closeErr, "failed to Close").Err() |
133 } | 125 } |
134 }() | 126 }() |
135 | 127 |
136 // Emit a series of "Distribution==Version" strings. | 128 // Emit a series of "Distribution==Version" strings. |
137 seen := make(map[Name]struct{}, len(wheels)) | 129 seen := make(map[Name]struct{}, len(wheels)) |
138 for _, wheel := range wheels { | 130 for _, wheel := range wheels { |
139 // Only mention a given Distribution/Version once. | 131 // Only mention a given Distribution/Version once. |
140 archetype := Name{ | 132 archetype := Name{ |
141 Distribution: wheel.Distribution, | 133 Distribution: wheel.Distribution, |
142 Version: wheel.Version, | 134 Version: wheel.Version, |
143 } | 135 } |
144 if _, ok := seen[archetype]; ok { | 136 if _, ok := seen[archetype]; ok { |
145 // Already seen a package for this archetype, skip it. | 137 // Already seen a package for this archetype, skip it. |
146 continue | 138 continue |
147 } | 139 } |
148 seen[archetype] = struct{}{} | 140 seen[archetype] = struct{}{} |
149 | 141 |
150 if _, err := fmt.Fprintf(fd, "%s==%s\n", archetype.Distribution,
archetype.Version); err != nil { | 142 if _, err := fmt.Fprintf(fd, "%s==%s\n", archetype.Distribution,
archetype.Version); err != nil { |
151 » » » return errors.Annotate(err).Reason("failed to write to r
equirements file").Err() | 143 » » » return errors.Annotate(err, "failed to write to requirem
ents file").Err() |
152 } | 144 } |
153 } | 145 } |
154 | 146 |
155 return nil | 147 return nil |
156 } | 148 } |
OLD | NEW |