| 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 |