|
14 | 14 | package command |
15 | 15 |
|
16 | 16 | import ( |
17 | | - "context" |
18 | 17 | "fmt" |
19 | | - "io/ioutil" |
20 | | - "os" |
21 | | - "os/signal" |
22 | | - "path/filepath" |
23 | 18 | "sort" |
24 | 19 | "strings" |
25 | | - "syscall" |
26 | | - "time" |
27 | 20 |
|
28 | | - "golang.org/x/mod/modfile" |
29 | 21 | k8sversion "k8s.io/apimachinery/pkg/version" |
30 | 22 |
|
31 | 23 | ackgenconfig "github.com/aws-controllers-k8s/code-generator/pkg/config" |
32 | 24 | ackgenerate "github.com/aws-controllers-k8s/code-generator/pkg/generate/ack" |
33 | 25 | ackmetadata "github.com/aws-controllers-k8s/code-generator/pkg/metadata" |
34 | 26 | ackmodel "github.com/aws-controllers-k8s/code-generator/pkg/model" |
35 | 27 | acksdk "github.com/aws-controllers-k8s/code-generator/pkg/sdk" |
36 | | - "github.com/aws-controllers-k8s/code-generator/pkg/util" |
37 | 28 | ) |
38 | 29 |
|
39 | | -const ( |
40 | | - sdkRepoURL = "https://github.com/aws/aws-sdk-go" |
41 | | - defaultGitCloneTimeout = 180 * time.Second |
42 | | - defaultGitFetchTimeout = 30 * time.Second |
43 | | -) |
44 | | - |
45 | | -func contextWithSigterm(ctx context.Context) (context.Context, context.CancelFunc) { |
46 | | - ctx, cancel := context.WithCancel(ctx) |
47 | | - signalCh := make(chan os.Signal, 1) |
48 | | - |
49 | | - // recreate the context.CancelFunc |
50 | | - cancelFunc := func() { |
51 | | - signal.Stop(signalCh) |
52 | | - cancel() |
53 | | - } |
54 | | - |
55 | | - // notify on SIGINT or SIGTERM |
56 | | - signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM) |
57 | | - go func() { |
58 | | - select { |
59 | | - case <-signalCh: |
60 | | - cancel() |
61 | | - case <-ctx.Done(): |
62 | | - } |
63 | | - }() |
64 | | - |
65 | | - return ctx, cancelFunc |
66 | | -} |
67 | | - |
68 | | -// ensureDir makes sure that a supplied directory exists and |
69 | | -// returns whether the directory already existed. |
70 | | -func ensureDir(fp string) (bool, error) { |
71 | | - fi, err := os.Stat(fp) |
72 | | - if err != nil { |
73 | | - if os.IsNotExist(err) { |
74 | | - return false, os.MkdirAll(fp, os.ModePerm) |
75 | | - } |
76 | | - return false, err |
77 | | - } |
78 | | - if !fi.IsDir() { |
79 | | - return false, fmt.Errorf("expected %s to be a directory", fp) |
80 | | - } |
81 | | - if !isDirWriteable(fp) { |
82 | | - return true, fmt.Errorf("%s is not a writeable directory", fp) |
83 | | - } |
84 | | - |
85 | | - return true, nil |
86 | | -} |
87 | | - |
88 | | -// isDirWriteable returns true if the supplied directory path is writeable, |
89 | | -// false otherwise |
90 | | -func isDirWriteable(fp string) bool { |
91 | | - testPath := filepath.Join(fp, "test") |
92 | | - f, err := os.Create(testPath) |
93 | | - if err != nil { |
94 | | - return false |
95 | | - } |
96 | | - f.Close() |
97 | | - os.Remove(testPath) |
98 | | - return true |
99 | | -} |
100 | | - |
101 | | -// ensureSDKRepo ensures that we have a git clone'd copy of the aws-sdk-go |
102 | | -// repository, which we use model JSON files from. Upon successful return of |
103 | | -// this function, the sdkDir global variable will be set to the directory where |
104 | | -// the aws-sdk-go is found. It will also optionally fetch all the remote tags |
105 | | -// and checkout the given tag. |
106 | | -func ensureSDKRepo( |
107 | | - ctx context.Context, |
108 | | - cacheDir string, |
109 | | - // A boolean instructing ensureSDKRepo whether to fetch the remote tags from |
110 | | - // the upstream repository |
111 | | - fetchTags bool, |
112 | | -) error { |
113 | | - var err error |
114 | | - srcPath := filepath.Join(cacheDir, "src") |
115 | | - if err = os.MkdirAll(srcPath, os.ModePerm); err != nil { |
116 | | - return err |
117 | | - } |
118 | | - |
119 | | - // Clone repository if it doen't exist |
120 | | - sdkDir = filepath.Join(srcPath, "aws-sdk-go") |
121 | | - if _, err := os.Stat(sdkDir); os.IsNotExist(err) { |
122 | | - |
123 | | - ctx, cancel := context.WithTimeout(ctx, defaultGitCloneTimeout) |
124 | | - defer cancel() |
125 | | - err = util.CloneRepository(ctx, sdkDir, sdkRepoURL) |
126 | | - if err != nil { |
127 | | - return fmt.Errorf("canot clone repository: %v", err) |
128 | | - } |
129 | | - } |
130 | | - |
131 | | - // Fetch all tags |
132 | | - if fetchTags { |
133 | | - ctx, cancel := context.WithTimeout(ctx, defaultGitFetchTimeout) |
134 | | - defer cancel() |
135 | | - err = util.FetchRepositoryTags(ctx, sdkDir) |
136 | | - if err != nil { |
137 | | - return fmt.Errorf("cannot fetch tags: %v", err) |
138 | | - } |
139 | | - } |
140 | | - |
141 | | - // get sdkVersion and ensure it prefix |
142 | | - // TODO(a-hilaly) Parse `ack-generate-metadata.yaml` and pass the aws-sdk-go |
143 | | - // version here. |
144 | | - sdkVersion, err := getSDKVersion("") |
145 | | - if err != nil { |
146 | | - return err |
147 | | - } |
148 | | - sdkVersion = ensureSemverPrefix(sdkVersion) |
149 | | - |
150 | | - repo, err := util.LoadRepository(sdkDir) |
151 | | - if err != nil { |
152 | | - return fmt.Errorf("cannot read local repository: %v", err) |
153 | | - } |
154 | | - |
155 | | - // Now checkout the local repository. |
156 | | - err = util.CheckoutRepositoryTag(repo, sdkVersion) |
157 | | - if err != nil { |
158 | | - return fmt.Errorf("cannot checkout tag: %v", err) |
159 | | - } |
160 | | - |
161 | | - return err |
162 | | -} |
163 | | - |
164 | | -// ensureSemverPrefix takes a semver string and tries to append the 'v' |
165 | | -// prefix if it's missing. |
166 | | -func ensureSemverPrefix(s string) string { |
167 | | - // trim all leading 'v' runes (characters) |
168 | | - s = strings.TrimLeft(s, "v") |
169 | | - return fmt.Sprintf("v%s", s) |
170 | | -} |
171 | | - |
172 | | -// getSDKVersion returns the github.com/aws/aws-sdk-go version to use. It |
173 | | -// first tries to get the version from the --aws-sdk-go-version flag, then |
174 | | -// from the ack-generate-metadata.yaml and finally look for the service |
175 | | -// go.mod controller. |
176 | | -func getSDKVersion( |
177 | | - lastGenerationVersion string, |
178 | | -) (string, error) { |
179 | | - // First try to get the version from --aws-sdk-go-version flag |
180 | | - if optAWSSDKGoVersion != "" { |
181 | | - return optAWSSDKGoVersion, nil |
182 | | - } |
183 | | - |
184 | | - // then, try to use last generation version (from ack-generate-metadata.yaml) |
185 | | - if lastGenerationVersion != "" { |
186 | | - return lastGenerationVersion, nil |
187 | | - } |
188 | | - |
189 | | - // then, try to parse the service controller go.mod file |
190 | | - sdkVersion, err := getSDKVersionFromGoMod(filepath.Join(optOutputPath, "go.mod")) |
191 | | - if err == nil { |
192 | | - return sdkVersion, nil |
193 | | - } |
194 | | - |
195 | | - return "", err |
196 | | -} |
197 | | - |
198 | | -// getSDKVersionFromGoMod parses a given go.mod file and returns |
199 | | -// the aws-sdk-go version in the required modules. |
200 | | -func getSDKVersionFromGoMod(goModPath string) (string, error) { |
201 | | - b, err := ioutil.ReadFile(goModPath) |
202 | | - if err != nil { |
203 | | - return "", err |
204 | | - } |
205 | | - goMod, err := modfile.Parse("", b, nil) |
206 | | - if err != nil { |
207 | | - return "", err |
208 | | - } |
209 | | - sdkModule := strings.TrimPrefix(sdkRepoURL, "https://") |
210 | | - for _, require := range goMod.Require { |
211 | | - if require.Mod.Path == sdkModule { |
212 | | - return require.Mod.Version, nil |
213 | | - } |
214 | | - } |
215 | | - return "", fmt.Errorf("couldn't find %s in the go.mod require block", sdkModule) |
216 | | -} |
217 | | - |
218 | 30 | // loadModelWithLatestAPIVersion finds the AWS SDK for a given service alias and |
219 | 31 | // creates a new model with the latest API version. |
220 | 32 | func loadModelWithLatestAPIVersion(svcAlias string, metadata *ackmetadata.ServiceMetadata) (*ackmodel.Model, error) { |
|
0 commit comments