├── .gitignore
├── .travis.yml
├── .version.sh
├── CHANGELOG.md
├── LICENSE
├── README.e.md
├── README.md
├── Vagrantfile
├── _config.yml
├── appveyor-recipe.md
├── appveyor.yml
├── change.log
├── deb.json
├── glide.lock
├── glide.yaml
├── main.go
├── manifest
└── index.go
├── rpm.json
├── rtf
└── index.go
├── templates
├── LicenseAgreementDlg_HK.wxs
├── WixUI_HK.wxs
├── choco
│ ├── LICENSE.txt
│ ├── VERIFICATION.txt
│ ├── chocolateyInstall.ps1
│ ├── chocolateyUninstall.ps1
│ └── pkg.nuspec
└── product.wxs
├── testing
├── README.md
├── Vagrantfile
├── glide.lock
├── glide.yaml
├── hello
│ ├── LICENSE
│ ├── README.md
│ ├── assets
│ │ ├── dir1
│ │ │ └── file2
│ │ └── file1
│ ├── change.log
│ ├── glide.lock
│ ├── glide.yaml
│ ├── hello.go
│ ├── ico.ico
│ └── wix.json
├── main.go
├── test.bat
├── vagrant-off.sh
├── vagrant-setup.sh
└── vagrant-test.sh
├── tpls
└── index.go
├── unice-recipe.md
├── util
└── index.go
├── wix.json
└── wix
└── index.go
/.gitignore:
--------------------------------------------------------------------------------
1 | /.vagrant/
2 | /vendor/
3 | /notes.md
4 | /builder/
5 | /testing/demo/templates/
6 | /testing/demo/build/
7 | /testing/demo/pkg-build/
8 | /testing/test.exe
9 | /testing/.vagrant/
10 | /.glide/
11 | testing/vendor
12 | testing/hello/vendor
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 |
3 | services:
4 | - docker
5 |
6 | language: go
7 | go:
8 | - 1.9
9 |
10 | env:
11 | matrix:
12 | - OKARCH=amd64 OSARCH=amd64
13 | - OKARCH=386 OSARCH=i386
14 | global:
15 | - VERSION=${TRAVIS_TAG}
16 | - GH_USER=${TRAVIS_REPO_SLUG%/*}
17 | - GH_APP=${TRAVIS_REPO_SLUG#*/}
18 | - JFROG_CLI_OFFER_CONFIG=false
19 | # bintray token
20 | - secure: IRw6MHgW2lWOTywZVxn9rF5Sp91Iji/XJNT1dGs/gCogEojzE84K8OlWmPb090cGmJR+wv5wp0be5G34qYV0vssxseOVRZ4JZN0EqOOQGSPZxrbVc1aXMv4JKfe8SlBh18IG6O2bZW1uQHCpBz1QSygzG7o7wD1/j7q83PMxy4IMzfRNcbjRUmqK10/TMiDUuPTYXIAi5RKgrIghvfaIvtl3DG++BquhfYKex5u98kTcLDJ2eHTfWsl7UMcvHDamYVIDt5WFfPidfkkG8BXD5bwjgldGZ7CiXPevrslKeE5ZV3cjBRvSxcnGGOEE/hN9hhCiVCz/YJIc6v9QoTIRG9nv9RulCBAHsZJZXa3NymERioMi/+b5H7J3hluRSPpGHsGCefygi3lL7mq4lPhZAd78Rq6gkEG10sNcRjiP3nCsSFlTWIMyZmiTy27FvV9C8rCihAg0vMdx/mA0AWLDLjAvzSeNJAOiV6pXTDVIZVTiE82cTyqV9YrKZ9E7cxJz9mOfBEZ1AT5SRw6hFsQ7g+cPvscpL0l10S5WinfmGJzu+vjJ9RzYETSRrO1PUiOk4puyjW+AQmFy7CjL7lS7fL8xGsx3xENq1FW1NhRFP22jwA0wcWjXlDCRYzCLbuDBRfSasFZCQKEUTeOuvplTA/Yx62Es36TtgGKIwwYk+1U=
21 |
22 | before_install:
23 | - sudo add-apt-repository 'deb https://dl.bintray.com/mh-cbon/deb unstable main'
24 | - sudo apt-get -qq update
25 | - sudo apt-get install --allow-unauthenticated changelog go-bin-deb fakeroot
26 | - mkdir -p ${GOPATH}/bin
27 | - cd ~
28 | - curl https://glide.sh/get | sh
29 |
30 | install:
31 | - cd $GOPATH/src/github.com/$TRAVIS_REPO_SLUG
32 | - glide install
33 | - go install
34 |
35 | script:
36 | - echo "pass, ok."
37 |
38 | before_deploy:
39 | # create the deb package
40 | - cd $GOPATH/src/github.com/$TRAVIS_REPO_SLUG
41 | - mkdir -p build/$OSARCH
42 | - GOOS=linux go build --ldflags "-X main.VERSION=$VERSION" -o build/$OSARCH/$GH_APP main.go
43 | - go-bin-deb generate --file deb.json -a $OSARCH --version $VERSION -o $GH_APP-$OSARCH-$VERSION.deb
44 | # copy the deb for gh release (backward compatibility)
45 | - cp $GH_APP-$OSARCH-$VERSION.deb $GH_APP-$OKARCH.deb
46 | # upload to bintray
47 | - curl -fL https://getcli.jfrog.io | sh
48 | - ls -alh
49 | - ./jfrog bt pc --key=$BTKEY --user=$GH_USER --licenses=MIT --vcs-url=https://github.com/$GH_USER/deb $GH_USER/deb/$GH_APP || echo "package already exists"
50 | - ./jfrog bt upload --override=true --key $BTKEY --publish=true --deb=unstable/main/$OSARCH $GH_APP-$OSARCH-$VERSION.deb $GH_USER/deb/$GH_APP/$VERSION pool/g/$GH_APP/
51 | # prepare rpm package creation
52 | - docker pull fedora
53 | # create the package in the docker
54 | - >
55 | docker run -v $PWD:/mnt/travis fedora /bin/sh -c
56 | "cd /mnt/travis && (curl -s -L https://bintray.com/mh-cbon/rpm/rpm > /etc/yum.repos.d/w.repo) && dnf install go-bin-rpm changelog rpm-build -y --quiet && go-bin-rpm generate --file rpm.json -a $OSARCH --version $VERSION -o $GH_APP-$OSARCH-$VERSION.rpm"
57 | # copy the rpm for gh release (backward compatibility)
58 | - cp $GH_APP-$OSARCH-$VERSION.rpm $GH_APP-$OKARCH.rpm
59 | # upload to bintray
60 | - ./jfrog bt pc --key=$BTKEY --user=$GH_USER --licenses=MIT --vcs-url=https://github.com/$GH_USER/rpm $GH_USER/rpm/$GH_APP || echo "package already exists"
61 | - ./jfrog bt upload --override=true --key $BTKEY --publish=true $GH_APP-$OSARCH-$VERSION.rpm $GH_USER/rpm/$GH_APP/$VERSION pool/$POOL/$GH_APP/
62 | # generate the repo metadata
63 | - curl -X POST -u ${GH_USER}:${BTKEY} https://api.bintray.com/calc_metadata/${GH_USER}/rpm
64 |
65 | deploy:
66 | provider: releases
67 | api_key:
68 | secure: Dmi4to/C++oBkvIX2Q+hYvUkikb3au3T0jbhXDgl3WxCaz//TX28TJNzjYU/kR0etXGuQCwafPd8rUcWnz02X9ZUN2PG0Vx28BmOmQ3n7+1EDEkRTOP5e6vI6ZUSeti/YYsNjPLiw4UpQYcCIVCp07Cw4MlNfS/8IL5gcfnsQWU+YiBxG8zp6v6oz8utBpqa2Ax6JZ5aELoOiO7s11LB2M8VwbE3/drwz0ztEpAkocIGIq5zgG2SuG3yPKqA80Pimu/k96qxxlLy/ZBE+EYWz2JFaN88V9RO01l7ccYesENeYABK+iU0bI88UTFfY+QAU71zPB75u1dQpEP5K2u3OseaUhq59YObKBHKl6Z6mPb61SbdTeEokf2XEPBN3RTHPPKIYezxYKCavjGXkAXTQAR5FBZdvGZk04Kxw5jT13X+UzTxeo9gSkQGng4JgSIO4M1wJT+gPezbxYF7huIFFMGKUaCDy60PU0gN7HuDjkdcFwjdYfk5BQkeoaI8sUTp4fhHtjXjiVU8opk+LPIYd7muAV3tNtQz14P+0zQlceRimP2hAklVRF/8XdSq+X5f1bKnRnolSlSYj6x8laGOpE2cQ1CPfVQIkxMD9r9ZZmER4VHvhsgXHmuvhnjGIp36u5aT7uBhdtPocyZsW56KhuwMLpuePmy7ykQr+PI11z4=
69 | file_glob: true
70 | file:
71 | - $GH_APP-$OKARCH.deb
72 | - $GH_APP-$OKARCH.rpm
73 | skip_cleanup: true
74 | on:
75 | tags: true
76 |
--------------------------------------------------------------------------------
/.version.sh:
--------------------------------------------------------------------------------
1 | PREBUMP=
2 | 666 git fetch --tags origin master
3 | 666 git pull origin master
4 |
5 | PREVERSION=
6 | philea -s "666 go vet %s" "666 go-fmt-fail %s"
7 | go run main.go -v
8 | 666 changelog finalize --version !newversion!
9 | 666 commit -q -m "changelog: !newversion!" -f change.log
10 | 666 emd gen -out README.md
11 | 666 commit -q -m "README: !newversion!" -f README.md
12 |
13 | POSTVERSION=
14 | 666 changelog md -o CHANGELOG.md --guess
15 | 666 commit -q -m "changelog: !newversion!" -f CHANGELOG.md
16 | 666 go install --ldflags "-X main.VERSION=!newversion!"
17 | 666 git push
18 | 666 git push --tags
19 | 666 gh-api-cli create-release -n release -o mh-cbon -r go-msi \
20 | --ver !newversion! -c "changelog ghrelease --version !newversion!" \
21 | --draft !isprerelease!
22 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog - go-msi
2 |
3 | ### 1.0.2
4 |
5 | __Changes__
6 |
7 | - `go-msi set-guid`: close #22: add `--force,-f` flags.
8 | - `go-msi check-env`: display a report of your environment.
9 | - close #17 #27: improve error message when --msi flag is not provided in the command line
10 | - choco: packages now include `tools/VERIFICATION.txt` and `tools/LICENSE.txt` to the package.
11 |
12 | __Contributors__
13 |
14 | - mh-cbon
15 | - solvingJ
16 |
17 | Released by mh-cbon, Wed 23 Aug 2017 -
18 | [see the diff](https://github.com/mh-cbon/go-msi/compare/1.0.1...1.0.2#diff)
19 | ______________
20 |
21 | ### 1.0.1
22 |
23 | __Changes__
24 |
25 | - closes #2 Add support for (un)install hooks (run with elevated privileges)
26 | - workaround #9 Add support for services setup
27 | - closes #10 Add support for e2e tests with CI support
28 | - demo: add support for service
29 | - chocolatey: uninstall script, changed msiexec /qr argument to /q
30 | - testing: improve e2e tests to support services
31 | - testing: update vagrant scripts to run tests
32 | - package: make use of emd
33 | - package: change bump script to sh version
34 | - uuid(minor): close #7 remove useless code to generate an uuid
35 | - wix(minor): close #8 update product template to propagate environment variable changes
36 | - choco(minor): close #5 updated uninstaller script
37 |
38 | __Contributors__
39 |
40 | - Alfonso Acosta
41 | - mh-cbon
42 |
43 | Released by mh-cbon, Tue 07 Mar 2017 -
44 | [see the diff](https://github.com/mh-cbon/go-msi/compare/1.0.0...1.0.1#diff)
45 | ______________
46 |
47 | ### 1.0.0
48 |
49 | __Changes__
50 |
51 | - winters udpate, udpated documentation and lint
52 | - templates(minor): renamed Id and Guid properties,
53 | remove try-catch in chocoinstall,
54 | set CRLF instead OF LF eol
55 | - lint(break): renamed fields
56 | ChocoSpec.Id to ChocoSpec.ID
57 | Chocopec.ProjectUrl to Chocopec.ProjectURL
58 | ChocoSpec.LicenseUrl to ChocoSpec.LicenseURL
59 | ChocoSpec.IconUrl to ChocoSpec.IconURL
60 | WixFiles.Guid to WixFiles.GUID
61 | WixEnvList.Guid to WixEnvList.GUID
62 | WixShortcuts.Guid to WixShortcuts.GUID
63 | This change does not impact json file format.
64 | - choco(minor): on chocolatey reviewer request, geet ride of the try catch
65 |
66 | __Contributors__
67 |
68 | - mh-cbon
69 |
70 | Released by mh-cbon, Sun 08 Jan 2017 -
71 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.39...1.0.0#diff)
72 | ______________
73 |
74 | ### 0.0.39
75 |
76 | __Changes__
77 |
78 | - appveyor: update choco push key
79 | - choco: add checksum support. Closes #1
80 | - choco: fix pack command invokation, it was colliding with cmake
81 |
82 | __Contributors__
83 |
84 | - mh-cbon
85 |
86 | Released by mh-cbon, Mon 15 Aug 2016 -
87 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.38...0.0.39#diff)
88 | ______________
89 |
90 | ### 0.0.38
91 |
92 | __Changes__
93 |
94 | - choco: ensure tags always contains admin value to pass chocolatey validation
95 |
96 | __Contributors__
97 |
98 | - mh-cbon
99 |
100 | Released by mh-cbon, Fri 29 Jul 2016 -
101 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.37...0.0.38#diff)
102 | ______________
103 |
104 | ### 0.0.37
105 |
106 | __Changes__
107 |
108 | - Fix chocolatey package generation: Tags should not contain 'chocolatey' as a tag.
109 |
110 | __Contributors__
111 |
112 | - mh-cbon
113 |
114 | Released by mh-cbon, Fri 29 Jul 2016 -
115 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.36...0.0.37#diff)
116 | ______________
117 |
118 | ### 0.0.36
119 |
120 | __Changes__
121 |
122 | - travis: fix gh secure token
123 |
124 | __Contributors__
125 |
126 | - mh-cbon
127 |
128 | Released by mh-cbon, Fri 29 Jul 2016 -
129 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.35...0.0.36#diff)
130 | ______________
131 |
132 | ### 0.0.35
133 |
134 | __Changes__
135 |
136 | - rpm: fix templates path inlusion
137 | - README: update install section
138 |
139 | __Contributors__
140 |
141 | - mh-cbon
142 |
143 | Released by mh-cbon, Fri 29 Jul 2016 -
144 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.34...0.0.35#diff)
145 | ______________
146 |
147 | ### 0.0.34
148 |
149 | __Changes__
150 |
151 | - build: fix the msi file generation
152 | - appveyor: artifacts must be created in build_script section
153 |
154 | __Contributors__
155 |
156 | - mh-cbon
157 |
158 | Released by mh-cbon, Fri 29 Jul 2016 -
159 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.33...0.0.34#diff)
160 | ______________
161 |
162 | ### 0.0.33
163 |
164 | __Changes__
165 |
166 | - cli: add choco command to generate chocolatey packages.
167 | - Demo: add choco commands
168 | - build: update build scripts
169 |
170 | __Contributors__
171 |
172 | - mh-cbon
173 |
174 | Released by mh-cbon, Fri 29 Jul 2016 -
175 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.32...0.0.33#diff)
176 | ______________
177 |
178 | ### 0.0.32
179 |
180 | __Changes__
181 |
182 | - wix: fix minimum/maximum version value of UpgradeVersion field in the product template
183 |
184 | __Contributors__
185 |
186 | - mh-cbon
187 |
188 | Released by mh-cbon, Sat 23 Jul 2016 -
189 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.31...0.0.32#diff)
190 | ______________
191 |
192 | ### 0.0.31
193 |
194 | __Changes__
195 |
196 | - wix: fix version format for Product element field.
197 | When version value contains prerelease/metadata, it is not acceptable
198 | for wix. A new field is added to the manifest VersionOk containing the version
199 | string without prerelease/metadata value.
200 | product.wxs template now uses this new VersionOk field
201 | instead of the original Version field.
202 | - glide: add semver dependency
203 | - README: install section
204 |
205 | __Contributors__
206 |
207 | - mh-cbon
208 |
209 | Released by mh-cbon, Sat 23 Jul 2016 -
210 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.30...0.0.31#diff)
211 | ______________
212 |
213 | ### 0.0.30
214 |
215 | __Changes__
216 |
217 | - travis: template inclusion
218 |
219 | __Contributors__
220 |
221 | - mh-cbon
222 |
223 | Released by mh-cbon, Fri 15 Jul 2016 -
224 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.29...0.0.30#diff)
225 | ______________
226 |
227 | ### 0.0.29
228 |
229 | __Changes__
230 |
231 | - travis: fix missing changelog setup into docker image
232 |
233 | __Contributors__
234 |
235 | - mh-cbon
236 |
237 | Released by mh-cbon, Fri 15 Jul 2016 -
238 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.28...0.0.29#diff)
239 | ______________
240 |
241 | ### 0.0.28
242 |
243 | __Changes__
244 |
245 | - rpm: add missing docker support
246 |
247 | __Contributors__
248 |
249 | - mh-cbon
250 |
251 | Released by mh-cbon, Fri 15 Jul 2016 -
252 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.27...0.0.28#diff)
253 | ______________
254 |
255 | ### 0.0.27
256 |
257 | __Changes__
258 |
259 | - rpm: add rpm support
260 | - debian: remove useless urgency var
261 |
262 | __Contributors__
263 |
264 | - mh-cbon
265 |
266 | Released by mh-cbon, Fri 15 Jul 2016 -
267 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.26...0.0.27#diff)
268 | ______________
269 |
270 | ### 0.0.26
271 |
272 | __Changes__
273 |
274 | - travis: update deb installers
275 |
276 | __Contributors__
277 |
278 | - mh-cbon
279 |
280 | Released by mh-cbon, Fri 15 Jul 2016 -
281 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.25...0.0.26#diff)
282 | ______________
283 |
284 | ### 0.0.25
285 |
286 | __Changes__
287 |
288 | - Demo: add a demo with recipe commands
289 | - Code: add comments
290 | - Wix: Add Shortcuts icon support
291 | - Manifest: add icon support for shotcuts, add comments
292 | - wix.json: env var does not need to be set system wide
293 |
294 | __Contributors__
295 |
296 | - mh-cbon
297 |
298 | Released by mh-cbon, Fri 15 Jul 2016 -
299 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.24...0.0.25#diff)
300 | ______________
301 |
302 | ### 0.0.24
303 |
304 | __Changes__
305 |
306 | - travis: ensure changelog is installed
307 | - recipe: fix curl options and register go-msi PATH
308 | - appveyor: remove useless DIR command
309 | - appveyor: remove -v option to curl
310 |
311 | __Contributors__
312 |
313 | - mh-cbon
314 |
315 | Released by mh-cbon, Tue 12 Jul 2016 -
316 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.23...0.0.24#diff)
317 | ______________
318 |
319 | ### 0.0.23
320 |
321 | __Changes__
322 |
323 | - pkg: add deb package support
324 | - env: set env as system wide
325 | - main: add option for non windows built
326 | - appveyor: fix cur options to follow location redirects
327 | - release: add changelog support to release script
328 | - changelog: add new changelog
329 | - manifest: omit json fields when empty
330 | - wix.json: remove useless version field
331 | - README: add install from source section
332 | - recipes: improve commands and typos
333 |
334 | __Contributors__
335 |
336 | - mh-cbon
337 |
338 | Released by mh-cbon, Mon 11 Jul 2016 -
339 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.22...0.0.23#diff)
340 | ______________
341 |
342 | ### 0.0.22
343 |
344 | __Changes__
345 |
346 | - align arch arguments with GO standards
347 | - improve recipes commands and typos
348 |
349 | __Contributors__
350 |
351 | - mh-cbon
352 |
353 | Released by mh-cbon, Sun 26 Jun 2016 -
354 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.21...0.0.22#diff)
355 | ______________
356 |
357 | ### 0.0.21
358 |
359 | __Changes__
360 |
361 | - go fmt
362 | - improve recipes commands and typos
363 | - align arch arguments with GO standards
364 | - update recipes
365 |
366 | __Contributors__
367 |
368 | - mh-cbon
369 |
370 | Released by mh-cbon, Sun 26 Jun 2016 -
371 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.20...0.0.21#diff)
372 | ______________
373 |
374 | ### 0.0.20
375 |
376 | __Changes__
377 |
378 | - update appveyor recipe
379 | - tryfix for ldflags
380 |
381 | __Contributors__
382 |
383 | - mh-cbon
384 |
385 | Released by mh-cbon, Sun 26 Jun 2016 -
386 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.19...0.0.20#diff)
387 | ______________
388 |
389 | ### 0.0.19
390 |
391 | __Changes__
392 |
393 | - go fmt
394 | - fix path lookpath in guuid make for windows
395 | - Set version to the build
396 | - README
397 |
398 | __Contributors__
399 |
400 | - mh-cbon
401 |
402 | Released by mh-cbon, Sun 26 Jun 2016 -
403 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.18...0.0.19#diff)
404 | ______________
405 |
406 | ### 0.0.18
407 |
408 | __Changes__
409 |
410 | - go fmt
411 | - avoid variable shadowing
412 | - update recipes
413 |
414 | __Contributors__
415 |
416 | - mh-cbon
417 |
418 | Released by mh-cbon, Sun 26 Jun 2016 -
419 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.17...0.0.18#diff)
420 | ______________
421 |
422 | ### 0.0.17
423 |
424 | __Changes__
425 |
426 | - go fmt
427 |
428 | __Contributors__
429 |
430 | - mh-cbon
431 |
432 | Released by mh-cbon, Sat 25 Jun 2016 -
433 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.16...0.0.17#diff)
434 | ______________
435 |
436 | ### 0.0.16
437 |
438 | __Changes__
439 |
440 | - go fmt
441 |
442 | __Contributors__
443 |
444 | - mh-cbon
445 |
446 | Released by mh-cbon, Sat 25 Jun 2016 -
447 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.15...0.0.16#diff)
448 | ______________
449 |
450 | ### 0.0.15
451 |
452 | __Changes__
453 |
454 | - go fmt
455 | - fix HOWTOs
456 | - fix bin path detection
457 | - updates
458 |
459 | __Contributors__
460 |
461 | - mh-cbon
462 |
463 | Released by mh-cbon, Sat 25 Jun 2016 -
464 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.14...0.0.15#diff)
465 | ______________
466 |
467 | ### 0.0.14
468 |
469 | __Changes__
470 |
471 | - appveyor
472 |
473 | __Contributors__
474 |
475 | - mh-cbon
476 |
477 | Released by mh-cbon, Sat 25 Jun 2016 -
478 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.13...0.0.14#diff)
479 | ______________
480 |
481 | ### 0.0.13
482 |
483 | __Changes__
484 |
485 | - appveyor
486 |
487 | __Contributors__
488 |
489 | - mh-cbon
490 |
491 | Released by mh-cbon, Sat 25 Jun 2016 -
492 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.12...0.0.13#diff)
493 | ______________
494 |
495 | ### 0.0.12
496 |
497 | __Changes__
498 |
499 | - appveyor
500 |
501 | __Contributors__
502 |
503 | - mh-cbon
504 |
505 | Released by mh-cbon, Sat 25 Jun 2016 -
506 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.11...0.0.12#diff)
507 | ______________
508 |
509 | ### 0.0.11
510 |
511 | __Changes__
512 |
513 | - appveyor
514 |
515 | __Contributors__
516 |
517 | - mh-cbon
518 |
519 | Released by mh-cbon, Sat 25 Jun 2016 -
520 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.10...0.0.11#diff)
521 | ______________
522 |
523 | ### 0.0.10
524 |
525 | __Changes__
526 |
527 | - appveyor
528 |
529 | __Contributors__
530 |
531 | - mh-cbon
532 |
533 | Released by mh-cbon, Sat 25 Jun 2016 -
534 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.9...0.0.10#diff)
535 | ______________
536 |
537 | ### 0.0.9
538 |
539 | __Changes__
540 |
541 | - appveyor
542 |
543 | __Contributors__
544 |
545 | - mh-cbon
546 |
547 | Released by mh-cbon, Sat 25 Jun 2016 -
548 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.8...0.0.9#diff)
549 | ______________
550 |
551 | ### 0.0.8
552 |
553 | __Changes__
554 |
555 | - appveyor
556 |
557 | __Contributors__
558 |
559 | - mh-cbon
560 |
561 | Released by mh-cbon, Sat 25 Jun 2016 -
562 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.7...0.0.8#diff)
563 | ______________
564 |
565 | ### 0.0.7
566 |
567 | __Changes__
568 |
569 | - appveyor
570 |
571 | __Contributors__
572 |
573 | - mh-cbon
574 |
575 | Released by mh-cbon, Sat 25 Jun 2016 -
576 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.6...0.0.7#diff)
577 | ______________
578 |
579 | ### 0.0.6
580 |
581 | __Changes__
582 |
583 | - appveyor
584 |
585 | __Contributors__
586 |
587 | - mh-cbon
588 |
589 | Released by mh-cbon, Sat 25 Jun 2016 -
590 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.5...0.0.6#diff)
591 | ______________
592 |
593 | ### 0.0.5
594 |
595 | __Changes__
596 |
597 | - appveyor
598 |
599 | __Contributors__
600 |
601 | - mh-cbon
602 |
603 | Released by mh-cbon, Sat 25 Jun 2016 -
604 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.4...0.0.5#diff)
605 | ______________
606 |
607 | ### 0.0.4
608 |
609 | __Changes__
610 |
611 | - appveyor
612 |
613 | __Contributors__
614 |
615 | - mh-cbon
616 |
617 | Released by mh-cbon, Sat 25 Jun 2016 -
618 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.3...0.0.4#diff)
619 | ______________
620 |
621 | ### 0.0.3
622 |
623 | __Changes__
624 |
625 | - appveyor
626 | - appveyor
627 |
628 | __Contributors__
629 |
630 | - mh-cbon
631 |
632 | Released by mh-cbon, Sat 25 Jun 2016 -
633 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.2...0.0.3#diff)
634 | ______________
635 |
636 | ### 0.0.2
637 |
638 | __Changes__
639 |
640 | - appveyor
641 |
642 | __Contributors__
643 |
644 | - mh-cbon
645 |
646 | Released by mh-cbon, Sat 25 Jun 2016 -
647 | [see the diff](https://github.com/mh-cbon/go-msi/compare/0.0.1...0.0.2#diff)
648 | ______________
649 |
650 | ### 0.0.1
651 |
652 | __Changes__
653 |
654 | - Initial release
655 |
656 | __Contributors__
657 |
658 | - mh-cbon
659 |
660 | Released by mh-cbon, Sat 25 Jun 2016 -
661 | [see the diff](https://github.com/mh-cbon/go-msi/compare/f4041400c510163f8e0aa684d68ebbc3e9ad4e44...0.0.1#diff)
662 | ______________
663 |
664 |
665 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 西郷 隆盛
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.e.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # {{.Name}}
4 |
5 | {{template "badge/appveyor" .}}
6 |
7 | {{pkgdoc}}
8 |
9 | This tool is part of the [go-github-release workflow](https://github.com/mh-cbon/go-github-release)
10 |
11 | Find a demo program [here](https://github.com/mh-cbon/go-msi/tree/master/testing/hello)
12 |
13 | # {{toc 5}}
14 |
15 | # Install
16 |
17 | {{template "gh/releases" .}}
18 |
19 | #### Go
20 | {{template "go/install" .}}
21 |
22 | #### Bintray
23 | {{template "choco_bintray/install" .}}
24 |
25 | #### Chocolatey
26 | {{template "choco/install" .}}
27 |
28 | #### linux rpm/deb repository
29 | {{template "linux/bintray_repo" .}}
30 |
31 | #### linux rpm/deb standalone package
32 | {{template "linux/gh_pkg" .}}
33 |
34 | # Usage
35 |
36 | ### Requirements
37 |
38 | - A windows machine (see [here](https://github.com/mh-cbon/go-msi/blob/master/appveyor-recipe.md) for an appveyor file, see [here](https://github.com/mh-cbon/go-msi/blob/master/unice-recipe.md) for unix friendly users)
39 | - wix >= 3.10 (may work on older release, but it is untested, feel free to report)
40 | - you must add wix bin to your `PATH`
41 | - use `check-env` sub command to get a report.
42 |
43 | ### Workflow
44 |
45 | For simple cases,
46 |
47 | - Create a `wix.json` file like [this one](https://github.com/mh-cbon/go-msi/blob/master/wix.json)
48 | - Apply it guids with `go-msi set-guid`, you must do it once only for each app.
49 | - Run `go-msi make --msi your_program.msi --version 0.0.2`
50 |
51 | ### configuration file
52 |
53 | `wix.json` file describe the desired packaging rules between your sources and the resulting msi file.
54 |
55 | [Check the demo json file](https://github.com/mh-cbon/go-msi/blob/master/testing/hello/wix.json)
56 |
57 | Post an issue if it is not self-explanatory.
58 |
59 | Always double check the documentation and [SO](https://stackoverflow.com)
60 | when you face a difficulty with `heat`, `candle`, `light`
61 |
62 | - http://wixtoolset.org/documentation/
63 | - http://stackoverflow.com/questions/tagged/wix
64 |
65 | If you wonder why `INSTALLDIR`, `[INSTALLDIR]`, this is part of wix rules, please check their documentation.
66 |
67 | ### License file
68 |
69 | Take care to the license file, it must be an `rtf` file, it must be encoded with `Windows1252` charset.
70 |
71 | I have provided some tools to help with that matter.
72 |
73 | # Personnalization
74 |
75 | ### wix templates
76 |
77 | For simplicity a default install flow is provided, which you can find [here](https://github.com/mh-cbon/go-msi/tree/master/templates)
78 |
79 | You can create a new one for your own personalization,
80 | you should only take care to reproduce the go templating already
81 | defined for `files`, `directories`, `environment variables`, `license` and `shortcuts`.
82 |
83 | I guess most of your changes will be about the `WixUI_HK.wxs` file.
84 |
85 | # Cli
86 |
87 | ###### $ {{exec "go-msi" "-h" | color "sh"}}
88 |
89 | ###### $ {{exec "go-msi" "check-env" "-h" | color "sh"}}
90 |
91 | ###### $ {{exec "go-msi" "check-json" "-h" | color "sh"}}
92 |
93 | ###### $ {{exec "go-msi" "set-guid" "-h" | color "sh"}}
94 |
95 | ###### $ {{exec "go-msi" "make" "-h" | color "sh"}}
96 |
97 | ###### $ {{exec "go-msi" "choco" "-h" | color "sh"}}
98 |
99 | ###### $ {{exec "go-msi" "generate-templates" "-h" | color "sh"}}
100 |
101 | ###### $ {{exec "go-msi" "to-windows" "-h" | color "sh"}}
102 |
103 | ###### $ {{exec "go-msi" "to-rtf" "-h" | color "sh"}}
104 |
105 | ###### $ {{exec "go-msi" "gen-wix-cmd" "-h" | color "sh"}}
106 |
107 | ###### $ {{exec "go-msi" "run-wix-cmd" "-h" | color "sh"}}
108 |
109 | # Recipes
110 |
111 | ### Appveyor
112 |
113 | Please check [this](https://github.com/mh-cbon/go-msi/blob/master/appveyor-recipe.md)
114 |
115 | ### Unix like
116 |
117 | Please check [this](https://github.com/mh-cbon/go-msi/blob/master/unice-recipe.md)
118 |
119 | ### Release the project
120 |
121 | ```sh
122 | gump patch -d # check
123 | gump patch # bump
124 | ```
125 |
126 | # History
127 |
128 | [CHANGELOG](CHANGELOG.md)
129 |
130 | # Credits
131 |
132 | A big big thanks to
133 |
134 | - `Helge Klein`, which i do not know personally, but made this project possible by sharing a real world example at
135 | https://helgeklein.com/blog/2014/09/real-world-example-wix-msi-application-installer/
136 | - all SO contributors on `wix` tag.
137 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # go-msi
4 |
5 | [](https://ci.appveyor.com/project/mh-cbon/go-msi)
6 |
7 | Package go-msi helps to generate msi package for a Go project.
8 |
9 |
10 | This tool is part of the [go-github-release workflow](https://github.com/mh-cbon/go-github-release)
11 |
12 | Find a demo program [here](https://github.com/mh-cbon/go-msi/tree/master/testing/hello)
13 |
14 | # TOC
15 | - [Install](#install)
16 | - [Go](#go)
17 | - [Bintray](#bintray)
18 | - [Chocolatey](#chocolatey)
19 | - [linux rpm/deb repository](#linux-rpmdeb-repository)
20 | - [linux rpm/deb standalone package](#linux-rpmdeb-standalone-package)
21 | - [Usage](#usage)
22 | - [Requirements](#requirements)
23 | - [Workflow](#workflow)
24 | - [configuration file](#configuration-file)
25 | - [License file](#license-file)
26 | - [Personnalization](#personnalization)
27 | - [wix templates](#wix-templates)
28 | - [Cli](#cli)
29 | - [Recipes](#recipes)
30 | - [Appveyor](#appveyor)
31 | - [Unix like](#unix-like)
32 | - [Release the project](#release-the-project)
33 | - [History](#history)
34 | - [Credits](#credits)
35 |
36 | # Install
37 |
38 | Check the [release page](https://github.com/mh-cbon/go-msi/releases)!
39 |
40 | #### Go
41 | ```sh
42 | go get github.com/mh-cbon/go-msi
43 | ```
44 |
45 | #### Bintray
46 | ```sh
47 | choco source add -n=mh-cbon -s="https://api.bintray.com/nuget/mh-cbon/choco"
48 | choco install go-msi
49 | ```
50 |
51 | #### Chocolatey
52 | ```sh
53 | choco install go-msi
54 | ```
55 |
56 | #### linux rpm/deb repository
57 | ```sh
58 | wget -O - https://raw.githubusercontent.com/mh-cbon/latest/master/bintray.sh \
59 | | GH=mh-cbon/go-msi sh -xe
60 | # or
61 | curl -L https://raw.githubusercontent.com/mh-cbon/latest/master/bintray.sh \
62 | | GH=mh-cbon/go-msi sh -xe
63 | ```
64 |
65 | #### linux rpm/deb standalone package
66 | ```sh
67 | curl -L https://raw.githubusercontent.com/mh-cbon/latest/master/install.sh \
68 | | GH=mh-cbon/go-msi sh -xe
69 | # or
70 | wget -q -O - --no-check-certificate \
71 | https://raw.githubusercontent.com/mh-cbon/latest/master/install.sh \
72 | | GH=mh-cbon/go-msi sh -xe
73 | ```
74 |
75 | # Usage
76 |
77 | ### Requirements
78 |
79 | - A windows machine (see [here](https://github.com/mh-cbon/go-msi/blob/master/appveyor-recipe.md) for an appveyor file, see [here](https://github.com/mh-cbon/go-msi/blob/master/unice-recipe.md) for unix friendly users)
80 | - wix >= 3.10 (may work on older release, but it is untested, feel free to report)
81 | - you must add wix bin to your `PATH`
82 | - use `check-env` sub command to get a report.
83 |
84 | ### Workflow
85 |
86 | For simple cases,
87 |
88 | - Create a `wix.json` file like [this one](https://github.com/mh-cbon/go-msi/blob/master/wix.json)
89 | - Apply it guids with `go-msi set-guid`, you must do it once only for each app.
90 | - Run `go-msi make --msi your_program.msi --version 0.0.2`
91 |
92 | ### configuration file
93 |
94 | `wix.json` file describe the desired packaging rules between your sources and the resulting msi file.
95 |
96 | [Check the demo json file](https://github.com/mh-cbon/go-msi/blob/master/testing/hello/wix.json)
97 |
98 | Post an issue if it is not self-explanatory.
99 |
100 | Always double check the documentation and [SO](https://stackoverflow.com)
101 | when you face a difficulty with `heat`, `candle`, `light`
102 |
103 | - http://wixtoolset.org/documentation/
104 | - http://stackoverflow.com/questions/tagged/wix
105 |
106 | If you wonder why `INSTALLDIR`, `[INSTALLDIR]`, this is part of wix rules, please check their documentation.
107 |
108 | ### License file
109 |
110 | Take care to the license file, it must be an `rtf` file, it must be encoded with `Windows1252` charset.
111 |
112 | I have provided some tools to help with that matter.
113 |
114 | # Personnalization
115 |
116 | ### wix templates
117 |
118 | For simplicity a default install flow is provided, which you can find [here](https://github.com/mh-cbon/go-msi/tree/master/templates)
119 |
120 | You can create a new one for your own personalization,
121 | you should only take care to reproduce the go templating already
122 | defined for `files`, `directories`, `environment variables`, `license` and `shortcuts`.
123 |
124 | I guess most of your changes will be about the `WixUI_HK.wxs` file.
125 |
126 | # Cli
127 |
128 | ###### $ go-msi -h
129 | ```sh
130 | NAME:
131 | go-msi - Easy msi pakage for Go
132 |
133 | USAGE:
134 | go-msi
135 |
136 | VERSION:
137 | 0.0.0
138 |
139 | COMMANDS:
140 | check-json Check the JSON wix manifest
141 | check-env Provide a report about your environment setup
142 | set-guid Sets appropriate guids in your wix manifest
143 | generate-templates Generate wix templates
144 | to-windows Write Windows1252 encoded file
145 | to-rtf Write RTF formatted file
146 | gen-wix-cmd Generate a batch file of Wix commands to run
147 | run-wix-cmd Run the batch file of Wix commands
148 | make All-in-one command to make MSI files
149 | choco Generate a chocolatey package of your msi files
150 | help, h Shows a list of commands or help for one command
151 |
152 | GLOBAL OPTIONS:
153 | --help, -h show help
154 | --version, -v print the version
155 | ```
156 |
157 | ###### $ go-msi check-env -h
158 | ```sh
159 | NAME:
160 | go-msi check-env - Provide a report about your environment setup
161 |
162 | USAGE:
163 | go-msi check-env [arguments...]
164 | ```
165 |
166 | ###### $ go-msi check-json -h
167 | ```sh
168 | NAME:
169 | go-msi check-json - Check the JSON wix manifest
170 |
171 | USAGE:
172 | go-msi check-json [command options] [arguments...]
173 |
174 | OPTIONS:
175 | --path value, -p value Path to the wix manifest file (default: "wix.json")
176 | ```
177 |
178 | ###### $ go-msi set-guid -h
179 | ```sh
180 | NAME:
181 | go-msi set-guid - Sets appropriate guids in your wix manifest
182 |
183 | USAGE:
184 | go-msi set-guid [command options] [arguments...]
185 |
186 | OPTIONS:
187 | --path value, -p value Path to the wix manifest file (default: "wix.json")
188 | --force, -f Force update the guids
189 | ```
190 |
191 | ###### $ go-msi make -h
192 | ```sh
193 | NAME:
194 | go-msi make - All-in-one command to make MSI files
195 |
196 | USAGE:
197 | go-msi make [command options] [arguments...]
198 |
199 | OPTIONS:
200 | --path value, -p value Path to the wix manifest file (default: "wix.json")
201 | --src value, -s value Directory path to the wix templates files (default: "/home/mh-cbon/gow/bin/templates")
202 | --out value, -o value Directory path to the generated wix cmd file (default: "/tmp/go-msi645264968")
203 | --arch value, -a value A target architecture, amd64 or 386 (ia64 is not handled)
204 | --msi value, -m value Path to write resulting msi file to
205 | --version value The version of your program
206 | --license value, -l value Path to the license file
207 | --keep, -k Keep output directory containing build files (useful for debug)
208 | ```
209 |
210 | ###### $ go-msi choco -h
211 | ```sh
212 | NAME:
213 | go-msi choco - Generate a chocolatey package of your msi files
214 |
215 | USAGE:
216 | go-msi choco [command options] [arguments...]
217 |
218 | OPTIONS:
219 | --path value, -p value Path to the wix manifest file (default: "wix.json")
220 | --src value, -s value Directory path to the wix templates files (default: "/home/mh-cbon/gow/bin/templates/choco")
221 | --version value The version of your program
222 | --out value, -o value Directory path to the generated chocolatey build file (default: "/tmp/go-msi697894350")
223 | --input value, -i value Path to the msi file to package into the chocolatey package
224 | --changelog-cmd value, -c value A command to generate the content of the changlog in the package
225 | --keep, -k Keep output directory containing build files (useful for debug)
226 | ```
227 |
228 | ###### $ go-msi generate-templates -h
229 | ```sh
230 | NAME:
231 | go-msi generate-templates - Generate wix templates
232 |
233 | USAGE:
234 | go-msi generate-templates [command options] [arguments...]
235 |
236 | OPTIONS:
237 | --path value, -p value Path to the wix manifest file (default: "wix.json")
238 | --src value, -s value Directory path to the wix templates files (default: "/home/mh-cbon/gow/bin/templates")
239 | --out value, -o value Directory path to the generated wix templates files (default: "/tmp/go-msi522345138")
240 | --version value The version of your program
241 | --license value, -l value Path to the license file
242 | ```
243 |
244 | ###### $ go-msi to-windows -h
245 | ```sh
246 | NAME:
247 | go-msi to-windows - Write Windows1252 encoded file
248 |
249 | USAGE:
250 | go-msi to-windows [command options] [arguments...]
251 |
252 | OPTIONS:
253 | --src value, -s value Path to an UTF-8 encoded file
254 | --out value, -o value Path to the ANSI generated file
255 | ```
256 |
257 | ###### $ go-msi to-rtf -h
258 | ```sh
259 | NAME:
260 | go-msi to-rtf - Write RTF formatted file
261 |
262 | USAGE:
263 | go-msi to-rtf [command options] [arguments...]
264 |
265 | OPTIONS:
266 | --src value, -s value Path to a text file
267 | --out value, -o value Path to the RTF generated file
268 | --reencode, -e Also re encode UTF-8 to Windows1252 charset
269 | ```
270 |
271 | ###### $ go-msi gen-wix-cmd -h
272 | ```sh
273 | NAME:
274 | go-msi gen-wix-cmd - Generate a batch file of Wix commands to run
275 |
276 | USAGE:
277 | go-msi gen-wix-cmd [command options] [arguments...]
278 |
279 | OPTIONS:
280 | --path value, -p value Path to the wix manifest file (default: "wix.json")
281 | --src value, -s value Directory path to the wix templates files (default: "/home/mh-cbon/gow/bin/templates")
282 | --out value, -o value Directory path to the generated wix cmd file (default: "/tmp/go-msi844736928")
283 | --arch value, -a value A target architecture, amd64 or 386 (ia64 is not handled)
284 | --msi value, -m value Path to write resulting msi file to
285 | ```
286 |
287 | ###### $ go-msi run-wix-cmd -h
288 | ```sh
289 | NAME:
290 | go-msi run-wix-cmd - Run the batch file of Wix commands
291 |
292 | USAGE:
293 | go-msi run-wix-cmd [command options] [arguments...]
294 |
295 | OPTIONS:
296 | --out value, -o value Directory path to the generated wix cmd file (default: "/tmp/go-msi773158361")
297 | ```
298 |
299 | # Recipes
300 |
301 | ### Appveyor
302 |
303 | Please check [this](https://github.com/mh-cbon/go-msi/blob/master/appveyor-recipe.md)
304 |
305 | ### Unix like
306 |
307 | Please check [this](https://github.com/mh-cbon/go-msi/blob/master/unice-recipe.md)
308 |
309 | ### Release the project
310 |
311 | ```sh
312 | gump patch -d # check
313 | gump patch # bump
314 | ```
315 |
316 | # History
317 |
318 | [CHANGELOG](CHANGELOG.md)
319 |
320 | # Credits
321 |
322 | A big big thanks to
323 |
324 | - `Helge Klein`, which i do not know personally, but made this project possible by sharing a real world example at
325 | https://helgeklein.com/blog/2014/09/real-world-example-wix-msi-application-installer/
326 | - all SO contributors on `wix` tag.
327 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | Vagrant.configure("2") do |config|
5 |
6 | # on fedora-like, you must use the downloadable package of vagrant
7 | # available on hashi corp website.
8 | # The per distrib provided package wont provide winrm support..
9 | # see https://www.vagrantup.com/downloads.html
10 |
11 | config.vm.define :win2012 do |win|
12 | win.vm.box = "opentable/win-2012r2-standard-amd64-nocm"
13 | # big timeout since windows boot is very slow
14 | win.vm.boot_timeout = 500
15 | win.vm.communicator = :winrm
16 | win.vm.provider "virtualbox" do |vb|
17 | # first setup requires gui to be enabled so scripts can be executed in virtualbox guest screen
18 | vb.gui = false
19 | vb.gui = true
20 | vb.customize ["modifyvm", :id, "--memory", "1524"]
21 | vb.customize ["modifyvm", :id, "--vram", "128"]
22 | vb.customize ["modifyvm", :id, "--cpus", "1"]
23 | vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
24 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
25 | vb.customize ["guestproperty", "set", :id, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", 10000]
26 | end
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/appveyor-recipe.md:
--------------------------------------------------------------------------------
1 | # appveyor recipe to create msi package
2 |
3 | This is an HOWDOI build an msi package from a windows machine using appveyor cloud service.
4 |
5 |
6 | ### Requirements
7 |
8 | - a github account
9 | - a github repo
10 | - an appveyor account
11 |
12 |
13 | ### Repo setup
14 |
15 | 1. Add your repo to appveyor config
16 | 2. Generate a new Github API token (Settings->Personal access tokens->Generate new token). Give it authorizations to `repo`.
17 | 3. Save the new token!
18 | 3. Add a new `appveyor.yml` to the root of your repo
19 | 4. Encrypt the token value as an appveyor secure variable (AppVeyor->Dashboard->[Encrypt Data](https://ci.appveyor.com/tools/encrypt))
20 | 5. Modify below appveyor template
21 |
22 | __appveyor.yml__
23 |
24 | ```yml
25 | image: Visual Studio 2017
26 | clone_folder: c:\gopath\src\github.com\%APPVEYOR_REPO_NAME%
27 |
28 | # trigger build/deploy only on tag
29 | # if false, take care that %APPVEYOR_REPO_TAG_NAME% won t be set on commit
30 | # this will fail the build
31 | skip_non_tags: true
32 |
33 | environment:
34 | GOPATH: c:\gopath
35 | JFROG_CLI_OFFER_CONFIG: false
36 | VCS_URL: https://github.com/%APPVEYOR_REPO_NAME%
37 | BT_KEY:
38 | secure: yyyy
39 | CHOCOKEY:
40 | secure: xxxxx
41 |
42 | install:
43 | # wix setup
44 | - set PATH=%WIX%\bin;%PATH%
45 | # go setup
46 | - set PATH=%GOPATH%\bin;%PATH%
47 | # glide setup, if your package uses it
48 | - go get -u github.com/mh-cbon/never-fail
49 | - go get -u github.com/Masterminds/glide
50 | # setup go-msi, choose one method
51 | #
52 | # method 1: static link
53 | # - curl -fsSL -o C:\go-msi.msi https://github.com/mh-cbon/go-msi/releases/download/0.0.22/go-msi-amd64.msi
54 | # - msiexec.exe /i C:\go-msi.msi /quiet
55 | # - set PATH=C:\Program Files\go-msi\;%PATH% # for some reason, go-msi path needs to be added manually :(...
56 | #
57 | # method 2: via gh-api-cli
58 | # - curl -fsSL -o C:\latest.bat https://raw.githubusercontent.com/mh-cbon/latest/master/latest.bat
59 | # - cmd /C C:\latest.bat mh-cbon go-msi amd64
60 | # - set PATH=C:\Program Files\go-msi\;%PATH%
61 | #
62 | # method 3: via chocolatey
63 | - choco install changelog -y
64 | - choco install go-msi -y
65 | - glide install
66 |
67 |
68 | build_script:
69 | - set GH_APP=%APPVEYOR_PROJECT_NAME%
70 | - set GH_USER=%APPVEYOR_ACCOUNT_NAME%
71 | - set VERSION=%APPVEYOR_REPO_TAG_NAME%
72 | # - set VERSION=1.0.2 # fake it when needed
73 | - set GOARCH=386
74 | - go build -o %MYAPP%.exe --ldflags "-X main.VERSION=%VERSION%" main.go
75 | - .\go-msi.exe make --msi %GH_APP%-%GOARCH%.msi --version %VERSION% --arch %GOARCH%
76 | - set GOARCH=amd64
77 | - go build -o %MYAPP%.exe --ldflags "-X main.VERSION=%VERSION%" main.go
78 | - .\go-msi.exe make --msi %GH_APP%-%GOARCH%.msi --version %VERSION% --arch %GOARCH%
79 |
80 | after_deploy:
81 | # Choco push
82 | - .\go-msi.exe choco --input %GH_APP%-%GOARCH%.msi --version %VERSION% --changelog-cmd "changelog ghrelease --version %VERSION%"
83 | - choco push -k="'%CHOCOKEY%'" %GH_APP%.%VERSION%.nupkg
84 | # Bintray push
85 | - never-fail jfrog bt pc --user %GH_USER% --key %BT_KEY% --licenses=MIT --vcs-url=https://github.com/%APPVEYOR_REPO_NAME% %GH_USER%/msi/%GH_APP%
86 | - jfrog bt upload --user %GH_USER% --key %BT_KEY% --override=true --publish=true %GH_APP%-%GOARCH%-%VERSION%.msi %GH_USER%/msi/%GH_APP%/%VERSION%
87 | - never-fail jfrog bt pc --user %GH_USER% --key %BT_KEY% --licenses=MIT --vcs-url=https://github.com/%APPVEYOR_REPO_NAME% %GH_USER%/choco/%GH_APP%
88 | - jfrog bt upload --user %GH_USER% --key %BT_KEY% --override=true --publish=true %GH_APP%.%VERSION%.nupkg %GH_USER%/choco/%GH_APP%/%VERSION%
89 |
90 |
91 | # to disable automatic tests
92 | test: off
93 |
94 | # need this to deploy assets,
95 | # note that each MUST match only one file
96 | artifacts:
97 | - path: '*-386.msi'
98 | name: msi-x86
99 | - path: '*-amd64.msi'
100 | name: msi-x64
101 |
102 | # deploy section to github releases
103 | deploy:
104 | - provider: GitHub
105 | # it should be possible to use a regexp like this /msi.*/,
106 | # but I could not make it work, let me know if you find a solution
107 | artifact: msi-x86, msi-x64
108 | draft: false
109 | prerelease: false
110 | description: "Release {APPVEYOR_REPO_TAG_NAME}"
111 | auth_token:
112 | # Change this to your encrypted token value
113 | secure: xxxxx
114 | on:
115 | branch:
116 | - master
117 | - /v\d\.\d\.\d/
118 | - /\d\.\d\.\d/
119 | appveyor_repo_tag: true
120 | ```
121 |
122 | ### Workflow
123 |
124 | With this `appveyor.yml` config,
125 | every time you create a tag and push it on the remote,
126 | `msi` files are generated and uploaded to your github release.
127 |
128 | `choco` package is generated from the amd64 build,
129 | and uploaded to your choco account.
130 |
131 | Both `msi` nad `nupkg` artifacts are uploaded to your bintray repos (/msi/ and /choco/)
132 |
133 | [go here](https://ci.appveyor.com/tools/encrypt)
134 | to generate the secure variable containing your `choco` api key and your `bintray` key.
135 |
136 | For an easy way to bump,
137 | you can use [gump](https://github.com/mh-cbon/gump),
138 | with a script like this,
139 |
140 | ```yml
141 | scripts:
142 | prebump: 666 git fetch --tags
143 | preversion: |
144 | philea -s "666 go vet %s" "666 go-fmt-fail %s" \
145 | && go run main.go -v
146 | postversion: |
147 | 666 git push && 666 git push --tags \
148 | && 666 gh-api-cli create-release -n release -o YOURUSER -r YOURREPO --ver !newversion!
149 | ```
150 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Visual Studio 2017
2 | clone_folder: c:\gopath\src\github.com\%APPVEYOR_ACCOUNT_NAME%\%APPVEYOR_PROJECT_SLUG%
3 |
4 | # skip_non_tags: true
5 |
6 | # environment variables
7 | environment:
8 | GOPATH: c:\gopath
9 | JFROG_CLI_OFFER_CONFIG: false
10 | VCS_URL: https://github.com/%APPVEYOR_REPO_NAME%
11 | BT_KEY:
12 | secure: P9xGXGG38T4AvO8XXXXcbaDG2sSN4t6KH92zssGp0nrbyQAZuxHD9F84s6PM9mOD
13 | GH_TOKEN:
14 | secure: WVMaMjrLzXN8YNcnFRfcucTYWtvoDeE/4b2TUGQBZDvv7u+ERBQ///z5Q8qYSt0L
15 |
16 | install:
17 | - choco source add -n=mh-cbon -s="https://api.bintray.com/nuget/mh-cbon/choco"
18 | - choco install changelog gh-api-cli -y
19 | - refreshenv
20 | - set GH_APP=%APPVEYOR_PROJECT_NAME%
21 | - set GH_USER=%APPVEYOR_ACCOUNT_NAME%
22 | - set VERSION=%APPVEYOR_REPO_TAG_NAME%
23 | - if "%x%"=="%VERSION%" set VERSION=1.0.2
24 | - set PATH=%WIX%\bin;%PATH%
25 | - set PATH=%GOPATH%\bin;%PATH%
26 | - curl -fsSk -o jfrog.exe -L "https://api.bintray.com/content/jfrog/jfrog-cli-go/$latest/jfrog-cli-windows-amd64/jfrog.exe?bt_package=jfrog-cli-windows-amd64"
27 | - go get -u github.com/mh-cbon/never-fail
28 | - go get -u github.com/Masterminds/glide
29 | - glide install
30 |
31 | before_test:
32 | # do a manual installation of go-msi from pulled source code
33 | - mkdir C:\go-msi\
34 | - set GOARCH=amd64
35 | - go build -o C:\go-msi\go-msi.exe --ldflags "-X main.VERSION=%VERSION%" main.go
36 | - XCOPY /I /E templates C:\go-msi\templates
37 | # prepare tests packages
38 | - cd testing\\hello
39 | - glide install
40 | - cd ..
41 | - glide install
42 | - cd ..
43 | # run tests
44 | - go run testing\\main.go
45 | - cd && dir *msi
46 |
47 | # build msi artifacts
48 | build_script:
49 | # x386
50 | - set GOARCH=386
51 | - go build -o %GH_APP%.exe --ldflags "-X main.VERSION=%VERSION%" main.go
52 | - .\go-msi.exe make --msi %GH_APP%-%GOARCH%-%VERSION%.msi --version %VERSION% --arch %GOARCH%
53 | - cp %GH_APP%-%GOARCH%-%VERSION%.msi %GH_APP%-%GOARCH%.msi
54 | # nuget package is built only for the x86 arch.
55 | - .\go-msi.exe choco --path wix.json --version %VERSION% --input %GH_APP%-%GOARCH%-%VERSION%.msi --changelog-cmd "changelog ghrelease --version %VERSION%"
56 | # amd64
57 | - set GOARCH=amd64
58 | - go build -o %GH_APP%.exe --ldflags "-X main.VERSION=%VERSION%" main.go
59 | - .\go-msi.exe make --msi %GH_APP%-%GOARCH%-%VERSION%.msi --version %VERSION% --arch %GOARCH%
60 | - cp %GH_APP%-%GOARCH%-%VERSION%.msi %GH_APP%-%GOARCH%.msi
61 |
62 | deploy_script:
63 | - never-fail jfrog bt pc --user %GH_USER% --key %BT_KEY% --licenses=MIT --vcs-url=https://github.com/%APPVEYOR_REPO_NAME% %GH_USER%/msi/%GH_APP%
64 | - never-fail jfrog bt pc --user %GH_USER% --key %BT_KEY% --licenses=MIT --vcs-url=https://github.com/%APPVEYOR_REPO_NAME% %GH_USER%/choco/%GH_APP%
65 | - never-fail curl -X "DELETE" -u%GH_USER%:%BT_KEY% https://api.bintray.com/content/%GH_USER%/choco/%GH_APP%.%VERSION%.nupkg # workaround until --override=true is honored in next upload
66 | - jfrog bt upload --user %GH_USER% --key %BT_KEY% --override=true --publish=true %GH_APP%.%VERSION%.nupkg %GH_USER%/choco/%GH_APP%/%VERSION%
67 | - set GOARCH=386
68 | - jfrog bt upload --user %GH_USER% --key %BT_KEY% --override=true --publish=true %GH_APP%-%GOARCH%-%VERSION%.msi %GH_USER%/msi/%GH_APP%/%VERSION%
69 | - set GOARCH=amd64
70 | - jfrog bt upload --user %GH_USER% --key %BT_KEY% --override=true --publish=true %GH_APP%-%GOARCH%-%VERSION%.msi %GH_USER%/msi/%GH_APP%/%VERSION%
71 | # next section is a workaround for https://github.com/appveyor/ci/issues/1752
72 | - never-fail gh-api-cli upload-release-asset -t %GH_TOKEN% -g "*-386.msi" -o %GH_USER% -r %GH_APP% --ver %VERSION%
73 | - never-fail gh-api-cli upload-release-asset -t %GH_TOKEN% -g "*-amd64.msi" -o %GH_USER% -r %GH_APP% --ver %VERSION%
74 |
75 | artifacts:
76 | - path: '*-386.msi'
77 | name: msi-x86
78 | - path: '*-amd64.msi'
79 | name: msi-x64
80 |
81 | deploy:
82 | - provider: GitHub
83 | artifact: msi-x86, msi-x64
84 | draft: false
85 | prerelease: false
86 | desription: "Release %APPVEYOR_REPO_TAG_NAME%"
87 | auth_token:
88 | secure: WVMaMjrLzXN8YNcnFRfcucTYWtvoDeE/4b2TUGQBZDvv7u+ERBQ///z5Q8qYSt0L
89 | on:
90 | appveyor_repo_tag: true # deploy on tag push only
91 |
--------------------------------------------------------------------------------
/change.log:
--------------------------------------------------------------------------------
1 |
2 | 1.0.2
3 |
4 | * `go-msi set-guid`: close #22: add `--force,-f` flags.
5 | * `go-msi check-env`: display a report of your environment.
6 | * close #17 #27: improve error message when --msi flag is not provided in the command line
7 | * choco: packages now include `tools/VERIFICATION.txt` and `tools/LICENSE.txt` to the package.
8 |
9 | - mh-cbon
10 | - solvingJ
11 |
12 | -- mh-cbon ; Wed, 23 Aug 2017 18:29:58 +0200
13 |
14 |
15 |
16 | 1.0.1
17 |
18 | * closes #2 Add support for (un)install hooks (run with elevated privileges)
19 | * workaround #9 Add support for services setup
20 | * closes #10 Add support for e2e tests with CI support
21 | * demo: add support for service
22 | * chocolatey: uninstall script, changed msiexec /qr argument to /q
23 | * testing: improve e2e tests to support services
24 | * testing: update vagrant scripts to run tests
25 | * package: make use of emd
26 | * package: change bump script to sh version
27 | * uuid(minor): close #7 remove useless code to generate an uuid
28 | * wix(minor): close #8 update product template to propagate environment variable changes
29 | * choco(minor): close #5 updated uninstaller script
30 |
31 | - Alfonso Acosta
32 | - mh-cbon
33 |
34 | -- mh-cbon ; Tue, 07 Mar 2017 17:21:16 +0100
35 |
36 |
37 |
38 | 1.0.0
39 |
40 | * winters udpate, udpated documentation and lint
41 | * templates(minor): renamed Id and Guid properties,
42 | remove try-catch in chocoinstall,
43 | set CRLF instead OF LF eol
44 | * lint(break): renamed fields
45 | ChocoSpec.Id to ChocoSpec.ID
46 | Chocopec.ProjectUrl to Chocopec.ProjectURL
47 | ChocoSpec.LicenseUrl to ChocoSpec.LicenseURL
48 | ChocoSpec.IconUrl to ChocoSpec.IconURL
49 | WixFiles.Guid to WixFiles.GUID
50 | WixEnvList.Guid to WixEnvList.GUID
51 | WixShortcuts.Guid to WixShortcuts.GUID
52 | This change does not impact json file format.
53 | * choco(minor): on chocolatey reviewer request, geet ride of the try catch
54 |
55 | - mh-cbon
56 |
57 | -- mh-cbon ; Sun, 08 Jan 2017 19:11:46 +0100
58 |
59 |
60 |
61 | 0.0.39
62 |
63 | * appveyor: update choco push key
64 | * choco: add checksum support. Closes #1
65 | * choco: fix pack command invokation, it was colliding with cmake
66 |
67 | - mh-cbon
68 |
69 | -- mh-cbon ; Mon, 15 Aug 2016 18:30:01 +0200
70 |
71 |
72 |
73 | 0.0.38
74 |
75 | * choco: ensure tags always contains admin value to pass chocolatey validation
76 |
77 | - mh-cbon
78 |
79 | -- mh-cbon ; Fri, 29 Jul 2016 20:06:03 +0200
80 |
81 |
82 |
83 | 0.0.37
84 |
85 | * Fix chocolatey package generation: Tags should not contain 'chocolatey' as a tag.
86 |
87 | - mh-cbon
88 |
89 | -- mh-cbon ; Fri, 29 Jul 2016 19:09:04 +0200
90 |
91 |
92 |
93 | 0.0.36
94 |
95 | * travis: fix gh secure token
96 |
97 | - mh-cbon
98 |
99 | -- mh-cbon ; Fri, 29 Jul 2016 18:56:09 +0200
100 |
101 |
102 |
103 | 0.0.35
104 |
105 | * rpm: fix templates path inlusion
106 | * README: update install section
107 |
108 | - mh-cbon
109 |
110 | -- mh-cbon ; Fri, 29 Jul 2016 18:42:52 +0200
111 |
112 |
113 |
114 | 0.0.34
115 |
116 | * build: fix the msi file generation
117 | * appveyor: artifacts must be created in build_script section
118 |
119 | - mh-cbon
120 |
121 | -- mh-cbon ; Fri, 29 Jul 2016 18:33:07 +0200
122 |
123 |
124 |
125 | 0.0.33
126 |
127 | * cli: add choco command to generate chocolatey packages.
128 | * Demo: add choco commands
129 | * build: update build scripts
130 |
131 | - mh-cbon
132 |
133 | -- mh-cbon ; Fri, 29 Jul 2016 18:23:59 +0200
134 |
135 |
136 |
137 | 0.0.32
138 |
139 | * wix: fix minimum/maximum version value of UpgradeVersion field in the product template
140 |
141 | - mh-cbon
142 |
143 | -- mh-cbon ; Sat, 23 Jul 2016 15:41:56 +0200
144 |
145 |
146 |
147 | 0.0.31
148 |
149 | * wix: fix version format for Product element field.
150 | When version value contains prerelease/metadata, it is not acceptable
151 | for wix. A new field is added to the manifest VersionOk containing the version
152 | string without prerelease/metadata value.
153 | product.wxs template now uses this new VersionOk field
154 | instead of the original Version field.
155 | * glide: add semver dependency
156 | * README: install section
157 |
158 | - mh-cbon
159 |
160 | -- mh-cbon ; Sat, 23 Jul 2016 15:34:40 +0200
161 |
162 |
163 |
164 | 0.0.30
165 |
166 | * travis: template inclusion
167 |
168 | - mh-cbon
169 |
170 | -- mh-cbon ; Fri, 15 Jul 2016 21:06:08 +0200
171 |
172 |
173 |
174 | 0.0.29
175 |
176 | * travis: fix missing changelog setup into docker image
177 |
178 | - mh-cbon
179 |
180 | -- mh-cbon ; Fri, 15 Jul 2016 20:55:39 +0200
181 |
182 |
183 |
184 | 0.0.28
185 |
186 | * rpm: add missing docker support
187 |
188 | - mh-cbon
189 |
190 | -- mh-cbon ; Fri, 15 Jul 2016 20:45:51 +0200
191 |
192 |
193 |
194 | 0.0.27
195 |
196 | * rpm: add rpm support
197 | * debian: remove useless urgency var
198 |
199 | - mh-cbon
200 |
201 | -- mh-cbon ; Fri, 15 Jul 2016 20:40:44 +0200
202 |
203 |
204 |
205 | 0.0.26
206 |
207 | * travis: update deb installers
208 |
209 | - mh-cbon
210 |
211 | -- mh-cbon ; Fri, 15 Jul 2016 19:36:46 +0200
212 |
213 |
214 |
215 | 0.0.25
216 |
217 | * Demo: add a demo with recipe commands
218 | * Code: add comments
219 | * Wix: Add Shortcuts icon support
220 | * Manifest: add icon support for shotcuts, add comments
221 | * wix.json: env var does not need to be set system wide
222 |
223 | - mh-cbon
224 |
225 | -- mh-cbon ; Fri, 15 Jul 2016 19:15:54 +0200
226 |
227 |
228 |
229 | 0.0.24
230 |
231 | * travis: ensure changelog is installed
232 | * recipe: fix curl options and register go-msi PATH
233 | * appveyor: remove useless DIR command
234 | * appveyor: remove -v option to curl
235 |
236 | - mh-cbon
237 |
238 | -- mh-cbon ; Tue, 12 Jul 2016 00:20:14 +0200
239 |
240 |
241 |
242 | 0.0.23
243 |
244 | * pkg: add deb package support
245 | * env: set env as system wide
246 | * main: add option for non windows built
247 | * appveyor: fix cur options to follow location redirects
248 | * release: add changelog support to release script
249 | * changelog: add new changelog
250 | * manifest: omit json fields when empty
251 | * wix.json: remove useless version field
252 | * README: add install from source section
253 | * recipes: improve commands and typos
254 |
255 | - mh-cbon
256 |
257 | -- mh-cbon ; Mon, 11 Jul 2016 23:57:07 +0200
258 |
259 |
260 |
261 | 0.0.22
262 |
263 | * align arch arguments with GO standards
264 | * improve recipes commands and typos
265 |
266 | - mh-cbon
267 |
268 | -- mh-cbon ; Sun, 26 Jun 2016 12:14:49 +0200
269 |
270 |
271 |
272 | 0.0.21
273 |
274 | * go fmt
275 | * improve recipes commands and typos
276 | * align arch arguments with GO standards
277 | * update recipes
278 |
279 | - mh-cbon
280 |
281 | -- mh-cbon ; Sun, 26 Jun 2016 12:08:59 +0200
282 |
283 |
284 |
285 | 0.0.20
286 |
287 | * update appveyor recipe
288 | * tryfix for ldflags
289 |
290 | - mh-cbon
291 |
292 | -- mh-cbon ; Sun, 26 Jun 2016 11:26:55 +0200
293 |
294 |
295 |
296 | 0.0.19
297 |
298 | * go fmt
299 | * fix path lookpath in guuid make for windows
300 | * Set version to the build
301 | * README
302 |
303 | - mh-cbon
304 |
305 | -- mh-cbon ; Sun, 26 Jun 2016 10:31:12 +0200
306 |
307 |
308 |
309 | 0.0.18
310 |
311 | * go fmt
312 | * avoid variable shadowing
313 | * update recipes
314 |
315 | - mh-cbon
316 |
317 | -- mh-cbon ; Sun, 26 Jun 2016 00:13:53 +0200
318 |
319 |
320 |
321 | 0.0.17
322 |
323 | * go fmt
324 |
325 | - mh-cbon
326 |
327 | -- mh-cbon ; Sat, 25 Jun 2016 23:41:59 +0200
328 |
329 |
330 |
331 | 0.0.16
332 |
333 | * go fmt
334 |
335 | - mh-cbon
336 |
337 | -- mh-cbon ; Sat, 25 Jun 2016 23:40:56 +0200
338 |
339 |
340 |
341 | 0.0.15
342 |
343 | * go fmt
344 | * fix HOWTOs
345 | * fix bin path detection
346 | * updates
347 |
348 | - mh-cbon
349 |
350 | -- mh-cbon ; Sat, 25 Jun 2016 23:28:40 +0200
351 |
352 |
353 |
354 | 0.0.14
355 |
356 | * appveyor
357 |
358 | - mh-cbon
359 |
360 | -- mh-cbon ; Sat, 25 Jun 2016 22:05:11 +0200
361 |
362 |
363 |
364 | 0.0.13
365 |
366 | * appveyor
367 |
368 | - mh-cbon
369 |
370 | -- mh-cbon ; Sat, 25 Jun 2016 22:00:52 +0200
371 |
372 |
373 |
374 | 0.0.12
375 |
376 | * appveyor
377 |
378 | - mh-cbon
379 |
380 | -- mh-cbon ; Sat, 25 Jun 2016 21:59:01 +0200
381 |
382 |
383 |
384 | 0.0.11
385 |
386 | * appveyor
387 |
388 | - mh-cbon
389 |
390 | -- mh-cbon ; Sat, 25 Jun 2016 21:52:11 +0200
391 |
392 |
393 |
394 | 0.0.10
395 |
396 | * appveyor
397 |
398 | - mh-cbon
399 |
400 | -- mh-cbon ; Sat, 25 Jun 2016 21:44:23 +0200
401 |
402 |
403 |
404 | 0.0.9
405 |
406 | * appveyor
407 |
408 | - mh-cbon
409 |
410 | -- mh-cbon ; Sat, 25 Jun 2016 21:17:43 +0200
411 |
412 |
413 |
414 | 0.0.8
415 |
416 | * appveyor
417 |
418 | - mh-cbon
419 |
420 | -- mh-cbon ; Sat, 25 Jun 2016 21:09:35 +0200
421 |
422 |
423 |
424 | 0.0.7
425 |
426 | * appveyor
427 |
428 | - mh-cbon
429 |
430 | -- mh-cbon ; Sat, 25 Jun 2016 21:04:38 +0200
431 |
432 |
433 |
434 | 0.0.6
435 |
436 | * appveyor
437 |
438 | - mh-cbon
439 |
440 | -- mh-cbon ; Sat, 25 Jun 2016 20:56:26 +0200
441 |
442 |
443 |
444 | 0.0.5
445 |
446 | * appveyor
447 |
448 | - mh-cbon
449 |
450 | -- mh-cbon ; Sat, 25 Jun 2016 20:51:23 +0200
451 |
452 |
453 |
454 | 0.0.4
455 |
456 | * appveyor
457 |
458 | - mh-cbon
459 |
460 | -- mh-cbon ; Sat, 25 Jun 2016 20:43:13 +0200
461 |
462 |
463 |
464 | 0.0.3
465 |
466 | * appveyor
467 | * appveyor
468 |
469 | - mh-cbon
470 |
471 | -- mh-cbon ; Sat, 25 Jun 2016 20:21:46 +0200
472 |
473 |
474 |
475 | 0.0.2
476 |
477 | * appveyor
478 |
479 | - mh-cbon
480 |
481 | -- mh-cbon ; Sat, 25 Jun 2016 20:12:08 +0200
482 |
483 |
484 |
485 | 0.0.1
486 |
487 | * Initial release
488 |
489 | - mh-cbon
490 |
491 | -- mh-cbon ; Sat, 25 Jun 2016 19:55:56 +0200
492 |
493 |
494 |
--------------------------------------------------------------------------------
/deb.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "go-msi",
3 | "maintainer": "mh-cbon ",
4 | "description": "Generate msi packages",
5 | "changelog-cmd": "changelog debian --vars='{\"name\":\"!name!\"}'",
6 | "homepage": "http://github.com/mh-cbon/!name!",
7 | "files": [
8 | {
9 | "from": "build/!arch!/!name!",
10 | "to": "/usr/bin",
11 | "base" : "build/!arch!/",
12 | "fperm": "0755"
13 | },
14 | {
15 | "from": "templates",
16 | "to": "/usr/share/!name!/"
17 | }
18 | ],
19 | "copyrights": [
20 | {
21 | "files": "*",
22 | "copyright": "2016 mh-cbon ",
23 | "license": "MIT",
24 | "file": "LICENSE"
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/glide.lock:
--------------------------------------------------------------------------------
1 | hash: ebc371608c61721e2c6b4a1728fcbe972ba7b103a4405104a78ea5c13c04a347
2 | updated: 2017-02-18T16:39:56.234882986+01:00
3 | imports:
4 | - name: github.com/Masterminds/semver
5 | version: 59c29afe1a994eacb71c833025ca7acf874bb1da
6 | - name: github.com/mattn/go-zglob
7 | version: 95345c4e1c0ebc9d16a3284177f09360f4d20fab
8 | subpackages:
9 | - fastwalk
10 | - name: github.com/mh-cbon/stringexec
11 | version: bc348d279f975052c5169eedf4efb1bc0469453f
12 | - name: github.com/satori/go.uuid
13 | version: 879c5887cd475cd7864858769793b2ceb0d44feb
14 | - name: github.com/urfave/cli
15 | version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6
16 | - name: golang.org/x/text
17 | version: 85c29909967d7f171f821e7a42e7b7af76fb9598
18 | subpackages:
19 | - encoding
20 | - encoding/charmap
21 | - encoding/internal
22 | - encoding/internal/identifier
23 | - runes
24 | - transform
25 | testImports: []
26 |
--------------------------------------------------------------------------------
/glide.yaml:
--------------------------------------------------------------------------------
1 | package: github.com/mh-cbon/go-msi
2 | import:
3 | - package: github.com/urfave/cli
4 | version: ^1.17.0
5 | - package: golang.org/x/text
6 | - package: github.com/mattn/go-zglob
7 | - package: github.com/Masterminds/semver
8 | version: ^1.1.1
9 | - package: github.com/mh-cbon/stringexec
10 | version: ~0.0.1
11 | - package: github.com/satori/go.uuid
12 | version: ^1.1.0
13 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // Package go-msi helps to generate msi package for a Go project.
2 | package main
3 |
4 | import (
5 | "fmt"
6 | "io/ioutil"
7 | "os"
8 | "os/exec"
9 | "path/filepath"
10 | "regexp"
11 | "strings"
12 |
13 | "github.com/Masterminds/semver"
14 | "github.com/mh-cbon/go-msi/manifest"
15 | "github.com/mh-cbon/go-msi/rtf"
16 | "github.com/mh-cbon/go-msi/tpls"
17 | "github.com/mh-cbon/go-msi/util"
18 | "github.com/mh-cbon/go-msi/wix"
19 | "github.com/mh-cbon/stringexec"
20 | "github.com/urfave/cli"
21 | )
22 |
23 | // VERSION holds the program version.
24 | var VERSION = "0.0.0"
25 |
26 | // TPLPATH points to the template directory on the target system.
27 | // Should be used only for non windows systems to indicate template locations.
28 | var TPLPATH = "" // non-windows build, use ldflags to tell about that.
29 |
30 | func main() {
31 |
32 | if TPLPATH == "" { // built for windows
33 | b, err := util.GetBinPath()
34 | if err != nil {
35 | panic(err)
36 | }
37 | TPLPATH = b
38 | }
39 | tmpBuildDir, err := ioutil.TempDir("", "go-msi")
40 | if err != nil {
41 | panic(err)
42 | }
43 |
44 | app := cli.NewApp()
45 | app.Name = "go-msi"
46 | app.Version = VERSION
47 | app.Usage = "Easy msi pakage for Go"
48 | app.UsageText = "go-msi "
49 | app.Commands = []cli.Command{
50 | {
51 | Name: "check-json",
52 | Usage: "Check the JSON wix manifest",
53 | Action: checkJSON,
54 | Flags: []cli.Flag{
55 | cli.StringFlag{
56 | Name: "path, p",
57 | Value: "wix.json",
58 | Usage: "Path to the wix manifest file",
59 | },
60 | },
61 | },
62 | {
63 | Name: "check-env",
64 | Usage: "Provide a report about your environment setup",
65 | Action: checkEnv,
66 | },
67 | {
68 | Name: "set-guid",
69 | Usage: "Sets appropriate guids in your wix manifest",
70 | Action: setGUID,
71 | Flags: []cli.Flag{
72 | cli.StringFlag{
73 | Name: "path, p",
74 | Value: "wix.json",
75 | Usage: "Path to the wix manifest file",
76 | },
77 | cli.BoolFlag{
78 | Name: "force, f",
79 | Usage: "Force update the guids",
80 | },
81 | },
82 | },
83 | {
84 | Name: "generate-templates",
85 | Usage: "Generate wix templates",
86 | Action: generateTemplates,
87 | Flags: []cli.Flag{
88 | cli.StringFlag{
89 | Name: "path, p",
90 | Value: "wix.json",
91 | Usage: "Path to the wix manifest file",
92 | },
93 | cli.StringFlag{
94 | Name: "src, s",
95 | Value: filepath.Join(TPLPATH, "templates"),
96 | Usage: "Directory path to the wix templates files",
97 | },
98 | cli.StringFlag{
99 | Name: "out, o",
100 | Value: tmpBuildDir,
101 | Usage: "Directory path to the generated wix templates files",
102 | },
103 | cli.StringFlag{
104 | Name: "version",
105 | Value: "",
106 | Usage: "The version of your program",
107 | },
108 | cli.StringFlag{
109 | Name: "license, l",
110 | Value: "",
111 | Usage: "Path to the license file",
112 | },
113 | },
114 | },
115 | {
116 | Name: "to-windows",
117 | Usage: "Write Windows1252 encoded file",
118 | Action: toWindows1252,
119 | Flags: []cli.Flag{
120 | cli.StringFlag{
121 | Name: "src, s",
122 | Value: "",
123 | Usage: "Path to an UTF-8 encoded file",
124 | },
125 | cli.StringFlag{
126 | Name: "out, o",
127 | Value: "",
128 | Usage: "Path to the ANSI generated file",
129 | },
130 | },
131 | },
132 | {
133 | Name: "to-rtf",
134 | Usage: "Write RTF formatted file",
135 | Action: toRtf,
136 | Flags: []cli.Flag{
137 | cli.StringFlag{
138 | Name: "src, s",
139 | Value: "",
140 | Usage: "Path to a text file",
141 | },
142 | cli.StringFlag{
143 | Name: "out, o",
144 | Value: "",
145 | Usage: "Path to the RTF generated file",
146 | },
147 | cli.BoolFlag{
148 | Name: "reencode, e",
149 | Usage: "Also re encode UTF-8 to Windows1252 charset",
150 | },
151 | },
152 | },
153 | {
154 | Name: "gen-wix-cmd",
155 | Usage: "Generate a batch file of Wix commands to run",
156 | Action: generateWixCommands,
157 | Flags: []cli.Flag{
158 | cli.StringFlag{
159 | Name: "path, p",
160 | Value: "wix.json",
161 | Usage: "Path to the wix manifest file",
162 | },
163 | cli.StringFlag{
164 | Name: "src, s",
165 | Value: filepath.Join(TPLPATH, "templates"),
166 | Usage: "Directory path to the wix templates files",
167 | },
168 | cli.StringFlag{
169 | Name: "out, o",
170 | Value: tmpBuildDir,
171 | Usage: "Directory path to the generated wix cmd file",
172 | },
173 | cli.StringFlag{
174 | Name: "arch, a",
175 | Value: "",
176 | Usage: "A target architecture, amd64 or 386 (ia64 is not handled)",
177 | },
178 | cli.StringFlag{
179 | Name: "msi, m",
180 | Value: "",
181 | Usage: "Path to write resulting msi file to",
182 | },
183 | },
184 | },
185 | {
186 | Name: "run-wix-cmd",
187 | Usage: "Run the batch file of Wix commands",
188 | Action: runWixCommands,
189 | Flags: []cli.Flag{
190 | cli.StringFlag{
191 | Name: "out, o",
192 | Value: tmpBuildDir,
193 | Usage: "Directory path to the generated wix cmd file",
194 | },
195 | },
196 | },
197 | {
198 | Name: "make",
199 | Usage: "All-in-one command to make MSI files",
200 | Action: quickMake,
201 | Flags: []cli.Flag{
202 | cli.StringFlag{
203 | Name: "path, p",
204 | Value: "wix.json",
205 | Usage: "Path to the wix manifest file",
206 | },
207 | cli.StringFlag{
208 | Name: "src, s",
209 | Value: filepath.Join(TPLPATH, "templates"),
210 | Usage: "Directory path to the wix templates files",
211 | },
212 | cli.StringFlag{
213 | Name: "out, o",
214 | Value: tmpBuildDir,
215 | Usage: "Directory path to the generated wix cmd file",
216 | },
217 | cli.StringFlag{
218 | Name: "arch, a",
219 | Value: "",
220 | Usage: "A target architecture, amd64 or 386 (ia64 is not handled)",
221 | },
222 | cli.StringFlag{
223 | Name: "msi, m",
224 | Value: "",
225 | Usage: "Path to write resulting msi file to",
226 | },
227 | cli.StringFlag{
228 | Name: "version",
229 | Value: "",
230 | Usage: "The version of your program",
231 | },
232 | cli.StringFlag{
233 | Name: "license, l",
234 | Value: "",
235 | Usage: "Path to the license file",
236 | },
237 | cli.BoolFlag{
238 | Name: "keep, k",
239 | Usage: "Keep output directory containing build files (useful for debug)",
240 | },
241 | },
242 | },
243 | {
244 | Name: "choco",
245 | Usage: "Generate a chocolatey package of your msi files",
246 | Action: chocoMake,
247 | Flags: []cli.Flag{
248 | cli.StringFlag{
249 | Name: "path, p",
250 | Value: "wix.json",
251 | Usage: "Path to the wix manifest file",
252 | },
253 | cli.StringFlag{
254 | Name: "src, s",
255 | Value: filepath.Join(TPLPATH, "templates", "choco"),
256 | Usage: "Directory path to the wix templates files",
257 | },
258 | cli.StringFlag{
259 | Name: "version",
260 | Value: "",
261 | Usage: "The version of your program",
262 | },
263 | cli.StringFlag{
264 | Name: "out, o",
265 | Value: tmpBuildDir,
266 | Usage: "Directory path to the generated chocolatey build file",
267 | },
268 | cli.StringFlag{
269 | Name: "input, i",
270 | Value: "",
271 | Usage: "Path to the msi file to package into the chocolatey package",
272 | },
273 | cli.StringFlag{
274 | Name: "changelog-cmd, c",
275 | Value: "",
276 | Usage: "A command to generate the content of the changlog in the package",
277 | },
278 | cli.BoolFlag{
279 | Name: "keep, k",
280 | Usage: "Keep output directory containing build files (useful for debug)",
281 | },
282 | },
283 | },
284 | }
285 |
286 | app.Run(os.Args)
287 | }
288 |
289 | var verReg = regexp.MustCompile(`\s[0-9]+[.][0-9]+[.][0-9]+`)
290 |
291 | func checkEnv(c *cli.Context) error {
292 |
293 | for _, b := range []string{"heat", "light", "candle"} {
294 | if out, err := util.Exec(b, "-h"); out == "" {
295 | fmt.Printf("!! %v not found: %q\n", b, err)
296 | } else {
297 | match := verReg.FindAllString(out, -1)
298 | if len(match) < 1 {
299 | fmt.Printf("?? %v probably not found\n", b)
300 | } else {
301 | version := strings.TrimSpace(match[0])
302 | ver, err := semver.NewVersion(version)
303 | if err != nil {
304 | fmt.Printf("?? %v found but its version is not parsable %v\n", b, version)
305 | } else {
306 | min := "3.10.0"
307 | if !ver.GreaterThan(semver.MustParse(min)) {
308 | fmt.Printf("!! %v found %v but %v is required\n", b, version, min)
309 | } else {
310 | fmt.Printf("ok %v found %v\n", b, version)
311 | }
312 | }
313 | }
314 | }
315 | }
316 | if out, err := util.Exec("choco", "-v"); out == "" {
317 | fmt.Printf("!! %v not found: %q\n", "chocolatey", err)
318 | } else {
319 | match := verReg.FindAllString(" "+out, -1)
320 | if len(match) < 1 {
321 | fmt.Printf("?? %v probably not found\n", "chocolatey")
322 | } else {
323 | version := strings.TrimSpace(match[0])
324 | ver, err := semver.NewVersion(version)
325 | if err != nil {
326 | fmt.Printf("?? %v found but its version is not parsable %v\n", "chocolatey", version)
327 | } else {
328 | min := "0.10.0"
329 | if !ver.GreaterThan(semver.MustParse(min)) {
330 | fmt.Printf("!! %v found %v but >%v is required\n", "chocolatey", version, min)
331 | } else {
332 | fmt.Printf("ok %v found %v\n", "chocolatey", version)
333 | }
334 | }
335 | }
336 | }
337 | return nil
338 | }
339 |
340 | func checkJSON(c *cli.Context) error {
341 | path := c.String("path")
342 |
343 | wixFile := manifest.WixManifest{}
344 | err := wixFile.Load(path)
345 | if err != nil {
346 | return cli.NewExitError(err.Error(), 1)
347 | }
348 |
349 | for _, hook := range wixFile.Hooks {
350 | if _, ok := manifest.HookPhases[hook.When]; !ok {
351 | return cli.NewExitError(`Invalid "when" value in hook: `+hook.When, 1)
352 | }
353 | }
354 |
355 | fmt.Println("The manifest is syntaxically correct !")
356 |
357 | if wixFile.NeedGUID() {
358 | fmt.Println("The manifest needs Guid")
359 | fmt.Println("To update your file automatically run:")
360 | fmt.Println(" go-msi set-guid")
361 | return cli.NewExitError("Incomplete manifest file detected", 1)
362 | }
363 | return nil
364 | }
365 |
366 | func setGUID(c *cli.Context) error {
367 | path := c.String("path")
368 | force := c.Bool("force")
369 |
370 | wixFile := manifest.WixManifest{}
371 | err := wixFile.Load(path)
372 | if err != nil {
373 | return cli.NewExitError(err.Error(), 1)
374 | }
375 |
376 | updated, err := wixFile.SetGuids(force)
377 | if err != nil {
378 | return cli.NewExitError(err.Error(), 1)
379 | }
380 |
381 | if updated {
382 | fmt.Println("The manifest was updated")
383 | } else {
384 | fmt.Println("The manifest was not updated")
385 | }
386 |
387 | err = wixFile.Write(path)
388 | if err != nil {
389 | return cli.NewExitError(err.Error(), 1)
390 | }
391 | fmt.Println("The file is saved on disk")
392 |
393 | return nil
394 | }
395 |
396 | func generateTemplates(c *cli.Context) error {
397 | path := c.String("path")
398 | src := c.String("src")
399 | out := c.String("out")
400 | version := c.String("version")
401 | license := c.String("license")
402 |
403 | wixFile := manifest.WixManifest{}
404 | err := wixFile.Load(path)
405 | if err != nil {
406 | return cli.NewExitError(err.Error(), 1)
407 | }
408 |
409 | if wixFile.NeedGUID() {
410 | fmt.Println("The manifest needs Guid")
411 | fmt.Println("To update your file automatically run:")
412 | fmt.Println(" go-msi set-guid")
413 | return cli.NewExitError("Cannot proceed, manifest file is incomplete", 1)
414 | }
415 |
416 | if c.IsSet("version") {
417 | wixFile.Version = version
418 | }
419 |
420 | if c.IsSet("license") {
421 | wixFile.License = license
422 | }
423 |
424 | err = wixFile.Normalize()
425 | if err != nil {
426 | return cli.NewExitError(err.Error(), 1)
427 | }
428 |
429 | err = wixFile.RewriteFilePaths(out)
430 | if err != nil {
431 | return cli.NewExitError(err.Error(), 1)
432 | }
433 |
434 | templates, err := tpls.Find(src, "*.wxs")
435 | if err != nil {
436 | return cli.NewExitError(err.Error(), 1)
437 | }
438 | if len(templates) == 0 {
439 | return cli.NewExitError("No templates *.wxs found in this directory", 1)
440 | }
441 |
442 | err = os.MkdirAll(out, 0744)
443 | if err != nil {
444 | return cli.NewExitError(err.Error(), 1)
445 | }
446 |
447 | for _, tpl := range templates {
448 | dst := filepath.Join(out, filepath.Base(tpl))
449 | err = tpls.GenerateTemplate(&wixFile, tpl, dst)
450 | if err != nil {
451 | return cli.NewExitError(err.Error(), 1)
452 | }
453 | }
454 |
455 | fmt.Printf("Generated %d templates\n", len(templates))
456 | for _, tpl := range templates {
457 | dst := filepath.Join(out, filepath.Base(tpl))
458 | fmt.Printf("- %s\n", dst)
459 | }
460 |
461 | return nil
462 | }
463 |
464 | func toWindows1252(c *cli.Context) error {
465 | src := c.String("src")
466 | out := c.String("out")
467 |
468 | if src == "" {
469 | return cli.NewExitError("--src argument is required", 1)
470 | }
471 | if out == "" {
472 | return cli.NewExitError("--out argument is required", 1)
473 | }
474 | if _, err := os.Stat(src); os.IsNotExist(err) {
475 | return cli.NewExitError(err.Error(), 1)
476 | }
477 | os.MkdirAll(filepath.Dir(out), 0744)
478 | err := rtf.WriteAsWindows1252(src, out)
479 | if err != nil {
480 | return cli.NewExitError(err.Error(), 1)
481 | }
482 | return nil
483 | }
484 |
485 | func toRtf(c *cli.Context) error {
486 | src := c.String("src")
487 | out := c.String("out")
488 | reencode := c.Bool("reencode")
489 |
490 | if src == "" {
491 | return cli.NewExitError("--src argument is required", 1)
492 | }
493 | if out == "" {
494 | return cli.NewExitError("--out argument is required", 1)
495 | }
496 | if _, err := os.Stat(src); os.IsNotExist(err) {
497 | return cli.NewExitError(err.Error(), 1)
498 | }
499 |
500 | os.MkdirAll(filepath.Dir(out), 0744)
501 |
502 | err := rtf.WriteAsRtf(src, out, reencode)
503 | if err != nil {
504 | return cli.NewExitError(err.Error(), 1)
505 | }
506 |
507 | return nil
508 | }
509 |
510 | func generateWixCommands(c *cli.Context) error {
511 | path := c.String("path")
512 | src := c.String("src")
513 | out := c.String("out")
514 | msi := c.String("msi")
515 | arch := c.String("arch")
516 |
517 | if msi == "" {
518 | return cli.NewExitError("--msi parameter must be set", 1)
519 | }
520 |
521 | templates, err := tpls.Find(src, "*.wxs")
522 | if err != nil {
523 | return cli.NewExitError(err.Error(), 1)
524 | }
525 | if len(templates) == 0 {
526 | return cli.NewExitError("No templates *.wxs found in this directory", 1)
527 | }
528 |
529 | builtTemplates := make([]string, len(templates))
530 | for i, tpl := range templates {
531 | builtTemplates[i] = filepath.Join(out, filepath.Base(tpl))
532 | }
533 |
534 | wixFile := manifest.WixManifest{}
535 | err = wixFile.Load(path)
536 | if err != nil {
537 | return cli.NewExitError(err.Error(), 1)
538 | }
539 |
540 | if wixFile.NeedGUID() {
541 | fmt.Println("The manifest needs Guid")
542 | fmt.Println("To update your file automatically run:")
543 | fmt.Println(" go-msi set-guid")
544 | return cli.NewExitError("Cannot proceed, manifest file is incomplete", 1)
545 | }
546 |
547 | err = wixFile.Normalize()
548 | if err != nil {
549 | return cli.NewExitError(err.Error(), 1)
550 | }
551 |
552 | err = wixFile.RewriteFilePaths(out)
553 | if err != nil {
554 | return cli.NewExitError(err.Error(), 1)
555 | }
556 |
557 | msi, err = filepath.Abs(msi)
558 | if err != nil {
559 | return cli.NewExitError(err.Error(), 1)
560 | }
561 | msi, err = filepath.Rel(out, msi)
562 | if err != nil {
563 | return cli.NewExitError(err.Error(), 1)
564 | }
565 |
566 | cmdStr := wix.GenerateCmd(&wixFile, builtTemplates, msi, arch)
567 |
568 | targetFile := filepath.Join(out, "build.bat")
569 | err = ioutil.WriteFile(targetFile, []byte(cmdStr), 0644)
570 | if err != nil {
571 | return cli.NewExitError(err.Error(), 1)
572 | }
573 |
574 | return nil
575 | }
576 |
577 | func runWixCommands(c *cli.Context) error {
578 | out := c.String("out")
579 |
580 | bin, err := exec.LookPath("cmd.exe")
581 | if err != nil {
582 | return cli.NewExitError(err.Error(), 1)
583 | }
584 | args := []string{"/C", "build.bat"}
585 | oCmd := exec.Command(bin, args...)
586 | oCmd.Dir = out
587 | oCmd.Stdout = os.Stdout
588 | oCmd.Stderr = os.Stderr
589 | err = oCmd.Run()
590 | if err != nil {
591 | return cli.NewExitError(err.Error(), 1)
592 | }
593 |
594 | return nil
595 | }
596 |
597 | func quickMake(c *cli.Context) error {
598 | path := c.String("path")
599 | src := c.String("src")
600 | out := c.String("out")
601 | version := c.String("version")
602 | license := c.String("license")
603 | msi := c.String("msi")
604 | arch := c.String("arch")
605 | keep := c.Bool("keep")
606 |
607 | if msi == "" {
608 | return cli.NewExitError("--msi parameter must be set", 1)
609 | }
610 |
611 | wixFile := manifest.WixManifest{}
612 | if err := wixFile.Load(path); err != nil {
613 | return cli.NewExitError(err.Error(), 1)
614 | }
615 |
616 | if wixFile.NeedGUID() {
617 | if _, err := wixFile.SetGuids(false); err != nil {
618 | return cli.NewExitError(err.Error(), 1)
619 | }
620 | }
621 |
622 | // if err := os.RemoveAll(out); err != nil {
623 | // return cli.NewExitError(err.Error(), 1)
624 | // }
625 | if err := os.MkdirAll(out, 0744); err != nil {
626 | return cli.NewExitError(err.Error(), 1)
627 | }
628 |
629 | if c.IsSet("version") {
630 | wixFile.Version = version
631 | }
632 |
633 | if c.IsSet("license") {
634 | wixFile.License = license
635 | }
636 |
637 | if err := wixFile.Normalize(); err != nil {
638 | return cli.NewExitError(err.Error(), 1)
639 | }
640 |
641 | if err := wixFile.RewriteFilePaths(out); err != nil {
642 | return cli.NewExitError(err.Error(), 1)
643 | }
644 |
645 | if wixFile.License != "" {
646 | if !rtf.IsRtf(wixFile.License) {
647 | target := filepath.Join(out, filepath.Base(wixFile.License)+".rtf")
648 | err := rtf.WriteAsRtf(wixFile.License, target, true)
649 | if err != nil {
650 | return cli.NewExitError(err.Error(), 1)
651 | }
652 | wixFile.License, err = filepath.Rel(out, target)
653 | if err != nil {
654 | return cli.NewExitError(err.Error(), 1)
655 | }
656 | }
657 | }
658 |
659 | templates, err := tpls.Find(src, "*.wxs")
660 | if err != nil {
661 | return cli.NewExitError(err.Error(), 1)
662 | }
663 | if len(templates) == 0 {
664 | return cli.NewExitError("No templates *.wxs found in this directory", 1)
665 | }
666 |
667 | builtTemplates := make([]string, len(templates))
668 | for i, tpl := range templates {
669 | dst := filepath.Join(out, filepath.Base(tpl))
670 | err = tpls.GenerateTemplate(&wixFile, tpl, dst)
671 | builtTemplates[i] = dst
672 | if err != nil {
673 | return cli.NewExitError(err.Error(), 1)
674 | }
675 | }
676 |
677 | msi, err = filepath.Abs(msi)
678 | if err != nil {
679 | return cli.NewExitError(err.Error(), 1)
680 | }
681 | msi, err = filepath.Rel(out, msi)
682 | if err != nil {
683 | return cli.NewExitError(err.Error(), 1)
684 | }
685 |
686 | cmdStr := wix.GenerateCmd(&wixFile, builtTemplates, msi, arch)
687 |
688 | targetFile := filepath.Join(out, "build.bat")
689 | err = ioutil.WriteFile(targetFile, []byte(cmdStr), 0644)
690 | if err != nil {
691 | return cli.NewExitError(err.Error(), 1)
692 | }
693 |
694 | bin, err := exec.LookPath("cmd.exe")
695 | if err != nil {
696 | return cli.NewExitError(err.Error(), 1)
697 | }
698 | args := []string{"/C", "build.bat"}
699 | oCmd := exec.Command(bin, args...)
700 | oCmd.Dir = out
701 | oCmd.Stdout = os.Stdout
702 | oCmd.Stderr = os.Stderr
703 | err = oCmd.Run()
704 | if err != nil {
705 | return cli.NewExitError(err.Error(), 1)
706 | }
707 |
708 | if keep == false {
709 | // err = os.RemoveAll(out)
710 | // if err != nil {
711 | // return cli.NewExitError(err.Error(), 1)
712 | // }
713 | } else {
714 | fmt.Printf("Build files are available in %s\n", out)
715 | }
716 |
717 | fmt.Println("All Done!!")
718 |
719 | return nil
720 | }
721 |
722 | func chocoMake(c *cli.Context) error {
723 | path := c.String("path")
724 | src := c.String("src")
725 | out := c.String("out")
726 | input := c.String("input")
727 | version := c.String("version")
728 | changelogCmd := c.String("changelog-cmd")
729 | keep := c.Bool("keep")
730 |
731 | wixFile := manifest.WixManifest{}
732 | if err := wixFile.Load(path); err != nil {
733 | return cli.NewExitError(err.Error(), 1)
734 | }
735 |
736 | if err := os.RemoveAll(out); err != nil {
737 | return cli.NewExitError(err.Error(), 1)
738 | }
739 | if err := os.MkdirAll(out, 0744); err != nil {
740 | return cli.NewExitError(err.Error(), 1)
741 | }
742 |
743 | if c.IsSet("version") {
744 | wixFile.Version = version
745 | }
746 |
747 | if err := wixFile.Normalize(); err != nil {
748 | return cli.NewExitError(err.Error(), 1)
749 | }
750 |
751 | templates, err := tpls.Find(src, "*")
752 | if err != nil {
753 | return cli.NewExitError(err.Error(), 1)
754 | }
755 | if len(templates) == 0 {
756 | return cli.NewExitError("No templates found in this directory", 1)
757 | }
758 |
759 | out, err = filepath.Abs(out)
760 | if err != nil {
761 | return cli.NewExitError(err.Error(), 1)
762 | }
763 | wixFile.Choco.BuildDir = out
764 | wixFile.Choco.MsiFile = filepath.Base(input)
765 | wixFile.Choco.MsiSum, err = util.ComputeSha256(input)
766 | if err != nil {
767 | return cli.NewExitError(err.Error(), 1)
768 | }
769 |
770 | if changelogCmd != "" {
771 | windows, err2 := stringexec.Command(changelogCmd)
772 | if err2 != nil {
773 | return cli.NewExitError(err.Error(), 1)
774 | }
775 | windows.Stderr = os.Stderr
776 | out, err3 := windows.Output()
777 | if err3 != nil {
778 | return cli.NewExitError(fmt.Sprintf("Failed to execute command to generate the changelog:%q\n%v", changelogCmd, err.Error()), 1)
779 | }
780 | sout := string(out)
781 | souts := strings.Split(sout, "\n")
782 | if len(souts) > 2 {
783 | souts = souts[2:] // why ? command line artifacts ? todo: put an explanation here.
784 | }
785 | sout = strings.Join(souts, "\n")
786 |
787 | wixFile.Choco.ChangeLog = sout
788 | }
789 |
790 | if err = util.CopyFile(filepath.Join(wixFile.Choco.BuildDir, wixFile.Choco.MsiFile), input); err != nil {
791 | return cli.NewExitError(err.Error(), 1)
792 | }
793 |
794 | for _, tpl := range templates {
795 | dst := filepath.Join(out, filepath.Base(tpl))
796 | err = tpls.GenerateTemplate(&wixFile, tpl, dst)
797 | if err != nil {
798 | return cli.NewExitError(err.Error(), 1)
799 | }
800 | }
801 |
802 | bin, err := exec.LookPath("choco")
803 | if err != nil {
804 | return cli.NewExitError(err.Error(), 1)
805 | }
806 | oCmd := exec.Command(bin, "pack")
807 | oCmd.Dir = out
808 | oCmd.Stdout = os.Stdout
809 | oCmd.Stderr = os.Stderr
810 | err = oCmd.Run()
811 | if err != nil {
812 | return cli.NewExitError(err.Error(), 1)
813 | }
814 |
815 | SrcNupkg := fmt.Sprintf("%s\\%s.%s.nupkg", out, wixFile.Choco.ID, wixFile.VersionOk)
816 | DstNupkg := fmt.Sprintf("%s.%s.nupkg", wixFile.Choco.ID, wixFile.Version)
817 |
818 | if err = util.CopyFile(DstNupkg, SrcNupkg); err != nil {
819 | return cli.NewExitError(err.Error(), 1)
820 | }
821 |
822 | if keep == false {
823 | err = os.RemoveAll(out)
824 | if err != nil {
825 | return cli.NewExitError(err.Error(), 1)
826 | }
827 | } else {
828 | fmt.Printf("Build files are available in %s\n", out)
829 | }
830 |
831 | fmt.Printf("Package copied to %s\n", DstNupkg)
832 | fmt.Println("All Done!!")
833 |
834 | return nil
835 | }
836 |
--------------------------------------------------------------------------------
/manifest/index.go:
--------------------------------------------------------------------------------
1 | package manifest
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "encoding/xml"
7 | "fmt"
8 | "io/ioutil"
9 | "os"
10 | "path/filepath"
11 | "strconv"
12 | "strings"
13 |
14 | "github.com/Masterminds/semver"
15 | "github.com/satori/go.uuid"
16 | )
17 |
18 | // WixManifest is the struct to decode a wix.json file.
19 | type WixManifest struct {
20 | Product string `json:"product"`
21 | Company string `json:"company"`
22 | Version string `json:"version,omitempty"`
23 | VersionOk string `json:"-"`
24 | License string `json:"license,omitempty"`
25 | UpgradeCode string `json:"upgrade-code"`
26 | Files WixFiles `json:"files,omitempty"`
27 | Directories []string `json:"directories,omitempty"`
28 | RelDirs []string `json:"-"`
29 | Env WixEnvList `json:"env,omitempty"`
30 | Shortcuts WixShortcuts `json:"shortcuts,omitempty"`
31 | Choco ChocoSpec `json:"choco,omitempty"`
32 | Hooks []Hook `json:"hooks,omitempty"`
33 | InstallHooks []Hook `json:"-"`
34 | UninstallHooks []Hook `json:"-"`
35 | }
36 |
37 | // ChocoSpec is the struct to decode the choco key of a wix.json file.
38 | type ChocoSpec struct {
39 | ID string `json:"id,omitempty"`
40 | Title string `json:"title,omitempty"`
41 | Authors string `json:"authors,omitempty"`
42 | Owners string `json:"owners,omitempty"`
43 | Description string `json:"description,omitempty"`
44 | ProjectURL string `json:"project-url,omitempty"`
45 | Tags string `json:"tags,omitempty"`
46 | LicenseURL string `json:"license-url,omitempty"`
47 | IconURL string `json:"icon-url,omitempty"`
48 | RequireLicense bool `json:"require-license,omitempty"`
49 | MsiFile string `json:"-"`
50 | MsiSum string `json:"-"`
51 | BuildDir string `json:"-"`
52 | ChangeLog string `json:"-"`
53 | }
54 |
55 | const (
56 | whenInstall = "install"
57 | whenUninstall = "uninstall"
58 | )
59 |
60 | // HookPhases describes known hook phases.
61 | var HookPhases = map[string]bool{
62 | whenInstall: true,
63 | whenUninstall: true,
64 | }
65 |
66 | // Hook describes a command to run on install / uninstall.
67 | type Hook struct {
68 | Command string `json:"command,omitempty"`
69 | CookedCommand string `json:"-"`
70 | When string `json:"when,omitempty"`
71 | }
72 |
73 | // WixFiles is the struct to decode files key of the wix.json file.
74 | type WixFiles struct {
75 | GUID string `json:"guid"`
76 | Items []string `json:"items"`
77 | }
78 |
79 | // WixEnvList is the struct to decode env key of the wix.json file.
80 | type WixEnvList struct {
81 | GUID string `json:"guid"`
82 | Vars []WixEnv `json:"vars"`
83 | }
84 |
85 | // WixEnv is the struct to decode env value of the wix.json file.
86 | type WixEnv struct {
87 | Name string `json:"name"`
88 | Value string `json:"value"`
89 | Permanent string `json:"permanent"`
90 | System string `json:"system"`
91 | Action string `json:"action"`
92 | Part string `json:"part"`
93 | }
94 |
95 | // WixShortcuts is the struct to decode shortcuts key of the wix.json file.
96 | type WixShortcuts struct {
97 | GUID string `json:"guid,omitempty"`
98 | Items []WixShortcut `json:"items,omitempty"`
99 | }
100 |
101 | // WixShortcut is the struct to decode shortcut value of the wix.json file.
102 | type WixShortcut struct {
103 | Name string `json:"name"`
104 | Description string `json:"description"`
105 | Target string `json:"target"`
106 | WDir string `json:"wdir"`
107 | Arguments string `json:"arguments"`
108 | Icon string `json:"icon"` // a path to the ico file, no space in it.
109 | }
110 |
111 | // Write the manifest to the given file,
112 | // if file is empty, writes to wix.json
113 | func (wixFile *WixManifest) Write(p string) error {
114 | if p == "" {
115 | p = "wix.json"
116 | }
117 | byt, err := json.MarshalIndent(wixFile, "", " ")
118 | if err != nil {
119 | return err
120 | }
121 | err = ioutil.WriteFile(p, byt, 0644)
122 | if err != nil {
123 | return err
124 | }
125 | return nil
126 | }
127 |
128 | // Load the manifest from given file path,
129 | // if the file path is empty, reads from wix.json
130 | func (wixFile *WixManifest) Load(p string) error {
131 | if p == "" {
132 | p = "wix.json"
133 | }
134 | if _, err := os.Stat(p); os.IsNotExist(err) {
135 | return err
136 | }
137 | dat, err := ioutil.ReadFile(p)
138 | if err != nil {
139 | return fmt.Errorf("JSON ReadFile failed with %v", err)
140 | }
141 | err = json.Unmarshal(dat, &wixFile)
142 | if err != nil {
143 | return fmt.Errorf("JSON Unmarshal failed with %v", err)
144 | }
145 | return nil
146 | }
147 |
148 | //SetGuids generates and apply guid values appropriately
149 | func (wixFile *WixManifest) SetGuids(force bool) (bool, error) {
150 | updated := false
151 | if wixFile.UpgradeCode == "" || force {
152 | wixFile.UpgradeCode = uuid.NewV4().String()
153 | updated = true
154 | }
155 | if wixFile.Files.GUID == "" || force {
156 | wixFile.Files.GUID = uuid.NewV4().String()
157 | updated = true
158 | }
159 | if (wixFile.Env.GUID == "" || force) && len(wixFile.Env.Vars) > 0 {
160 | wixFile.Env.GUID = uuid.NewV4().String()
161 | updated = true
162 | }
163 | if (wixFile.Shortcuts.GUID == "" || force) && len(wixFile.Shortcuts.Items) > 0 {
164 | wixFile.Shortcuts.GUID = uuid.NewV4().String()
165 | updated = true
166 | }
167 | return updated, nil
168 | }
169 |
170 | // NeedGUID tells if the manifest json file is missing guid values.
171 | func (wixFile *WixManifest) NeedGUID() bool {
172 | need := false
173 | if wixFile.UpgradeCode == "" {
174 | need = true
175 | }
176 | if wixFile.Files.GUID == "" {
177 | need = true
178 | }
179 | if wixFile.Env.GUID == "" && len(wixFile.Env.Vars) > 0 {
180 | need = true
181 | }
182 | if wixFile.Shortcuts.GUID == "" && len(wixFile.Shortcuts.Items) > 0 {
183 | need = true
184 | }
185 | return need
186 | }
187 |
188 | // RewriteFilePaths Reads Files and Directories of the wix.json file
189 | // and turn their values into a relative path to out
190 | // where out is the path to the wix templates files.
191 | func (wixFile *WixManifest) RewriteFilePaths(out string) error {
192 | var err error
193 | out, err = filepath.Abs(out)
194 | if err != nil {
195 | return err
196 | }
197 | for i, file := range wixFile.Files.Items {
198 | file, err = filepath.Abs(file)
199 | if err != nil {
200 | return err
201 | }
202 | wixFile.Files.Items[i], err = filepath.Rel(out, file)
203 | if err != nil {
204 | return err
205 | }
206 | }
207 | for _, d := range wixFile.Directories {
208 | d, err = filepath.Abs(d)
209 | if err != nil {
210 | return err
211 | }
212 | r, err := filepath.Rel(out, d)
213 | if err != nil {
214 | return err
215 | }
216 | wixFile.RelDirs = append(wixFile.RelDirs, r)
217 | }
218 | for i, s := range wixFile.Shortcuts.Items {
219 | if s.Icon != "" {
220 | file, err := filepath.Abs(s.Icon)
221 | if err != nil {
222 | return err
223 | }
224 | wixFile.Shortcuts.Items[i].Icon, err = filepath.Rel(out, file)
225 | if err != nil {
226 | return err
227 | }
228 | }
229 | }
230 | return nil
231 | }
232 |
233 | // Normalize Appropriately fixes some values within the decoded json
234 | // It applies defaults values on the wix/msi property to
235 | // to generate the msi package.
236 | // It applies defaults values on the choco property to
237 | // generate a nuget package
238 | func (wixFile *WixManifest) Normalize() error {
239 | // Wix version Field of Product element
240 | // does not support semver strings
241 | // it supports only something like x.x.x.x
242 | // So, if the version has metadata/prerelease values,
243 | // lets get ride of those and save the workable version
244 | // into VersionOk field
245 | wixFile.VersionOk = wixFile.Version
246 | v, err := semver.NewVersion(wixFile.Version)
247 | if err != nil {
248 | return fmt.Errorf("Failed to parse version '%v': %v", wixFile.Version, err)
249 | }
250 | okVersion := ""
251 | okVersion += strconv.FormatInt(v.Major(), 10)
252 | okVersion += "." + strconv.FormatInt(v.Minor(), 10)
253 | okVersion += "." + strconv.FormatInt(v.Patch(), 10)
254 | wixFile.VersionOk = okVersion
255 |
256 | // choco fix
257 | if wixFile.Choco.ID == "" {
258 | wixFile.Choco.ID = wixFile.Product
259 | }
260 | if wixFile.Choco.Title == "" {
261 | wixFile.Choco.Title = wixFile.Product
262 | }
263 | if wixFile.Choco.Authors == "" {
264 | wixFile.Choco.Authors = wixFile.Company
265 | }
266 | if wixFile.Choco.Owners == "" {
267 | wixFile.Choco.Owners = wixFile.Company
268 | }
269 | if wixFile.Choco.Description == "" {
270 | wixFile.Choco.Description = wixFile.Product
271 | }
272 | wixFile.Choco.Tags += " admin" // required to pass chocolatey validation..
273 |
274 | // Escape hook commands and ensure the command name is enclosed in quotes (needed by wix)
275 | for i, hook := range wixFile.Hooks {
276 | cmd := strings.Trim(hook.Command, " ")
277 | if len(cmd) > 0 && cmd[0] != '"' {
278 | words := strings.Split(cmd, " ")
279 | cmd = `"` + words[0] + `"` + cmd[len(words[0]):]
280 | }
281 | buf := &bytes.Buffer{}
282 | if err := xml.EscapeText(buf, []byte(cmd)); err != nil {
283 | return err
284 | }
285 | wixFile.Hooks[i].CookedCommand = buf.String()
286 | }
287 |
288 | // Separate install and uninstall hooks to simplify templating
289 | for _, hook := range wixFile.Hooks {
290 | switch hook.When {
291 | case whenInstall:
292 | wixFile.InstallHooks = append(wixFile.InstallHooks, hook)
293 | case whenUninstall:
294 | wixFile.UninstallHooks = append(wixFile.UninstallHooks, hook)
295 | }
296 | }
297 |
298 | return nil
299 | }
300 |
--------------------------------------------------------------------------------
/rpm.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "go-msi",
3 | "summary": "Generate msi packages",
4 | "description": "Generate msi packages",
5 | "changelog-cmd": "changelog rpm",
6 | "license": "LICENSE",
7 | "url": "https://github.com/mh-cbon/!name!",
8 | "files": [
9 | {
10 | "from": "build/!arch!/go-msi",
11 | "to": "%{_bindir}/",
12 | "base": "build/!arch!/",
13 | "type": ""
14 | },
15 | {
16 | "from": "templates/*/*",
17 | "to": "%{_datarootdir}/!name!/"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/rtf/index.go:
--------------------------------------------------------------------------------
1 | package rtf
2 |
3 | import (
4 | "io/ioutil"
5 | "strings"
6 | "unicode"
7 |
8 | "golang.org/x/text/encoding/charmap"
9 | "golang.org/x/text/runes"
10 | "golang.org/x/text/transform"
11 | )
12 |
13 | // WriteAsWindows1252 Reads given src file, encodes to windows1252
14 | // and writes the result to dst
15 | func WriteAsWindows1252(src string, dst string) error {
16 | bSrc, err := ioutil.ReadFile(src)
17 | if err != nil {
18 | return err
19 | }
20 |
21 | bDst := make([]byte, len(bSrc)*2)
22 | replaceNonASCII := runes.Map(func(r rune) rune {
23 | if r > unicode.MaxASCII {
24 | return rune('?')
25 | }
26 | return r
27 | })
28 | transformer := transform.Chain(replaceNonASCII, charmap.Windows1252.NewEncoder())
29 | _, _, err = transformer.Transform(bDst, bSrc, true)
30 | if err != nil {
31 | return err
32 | }
33 |
34 | dS := strings.NewReplacer("\r\n", "\r\n", "\n", "\r\n").Replace(string(bDst))
35 | return ioutil.WriteFile(dst, []byte(dS), 0644)
36 | }
37 |
38 | // WriteAsRtf Reads given src file and encodes it to windows1252,
39 | // formats the content to an RTF file
40 | // and writes the result to dst.
41 | func WriteAsRtf(src string, dst string, reencode bool) error {
42 |
43 | bSrc, err := ioutil.ReadFile(src)
44 | if err != nil {
45 | return err
46 | }
47 |
48 | var bDst []byte
49 |
50 | if reencode {
51 | bDst = make([]byte, len(bSrc))
52 | replaceNonASCII := runes.Map(func(r rune) rune {
53 | if r > unicode.MaxASCII {
54 | return rune('?')
55 | }
56 | return r
57 | })
58 | transformer := transform.Chain(replaceNonASCII, charmap.Windows1252.NewEncoder())
59 | _, _, err := transformer.Transform(bDst, bSrc, true)
60 | if err != nil {
61 | return err
62 | }
63 |
64 | dS := strings.NewReplacer("\r\n", "\r\n", "\n", "\r\n").Replace(string(bDst))
65 |
66 | bDst = []byte(dS)
67 |
68 | } else {
69 | bDst = bSrc
70 | }
71 |
72 | sDat := strings.NewReplacer("\n", "\n\\line ").Replace(string(bDst))
73 | sDat = "{\\rtf1\\ansi\r\n" + sDat + "\r\n}"
74 |
75 | return ioutil.WriteFile(dst, []byte(sDat), 0644)
76 | }
77 |
78 | // IsRtf Detects if the given src file is formatted with RTF format.
79 | func IsRtf(src string) bool {
80 | dat, err := ioutil.ReadFile(src)
81 | if err != nil {
82 | return false
83 | }
84 | sDat := string(dat)
85 | if len(sDat) > 4 {
86 | return sDat[0:5] == "{\\rtf"
87 | }
88 | return false
89 | }
90 |
--------------------------------------------------------------------------------
/templates/LicenseAgreementDlg_HK.wxs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/templates/WixUI_HK.wxs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
26 |
27 |
28 | 1
29 | "1"]]>
30 |
31 | 1
32 |
33 | NOT Installed
40 | Installed AND PATCH
41 |
42 | 1
43 | LicenseAccepted = "1"
44 |
45 | 1
46 | 1
47 | NOT WIXUI_DONTVALIDATEPATH
48 | "1"]]>
49 | WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"
50 |
51 | 1
52 | 1
53 |
54 | Installed
55 |
56 | 1
57 |
58 | 1
59 | 1
60 | 1
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/templates/choco/LICENSE.txt:
--------------------------------------------------------------------------------
1 | From: {{.Choco.LicenseURL}}
2 |
3 | LICENSE
4 |
5 | {{if gt (.License | len) 0}}
6 | {{.License | cat}}
7 | {{else if gt (.Choco.LicenseURL | len) 0}}
8 | {{.Choco.LicenseURL | download}}
9 | {{end}}
10 |
--------------------------------------------------------------------------------
/templates/choco/VERIFICATION.txt:
--------------------------------------------------------------------------------
1 | VERIFICATION
2 |
3 | To check the checksum of this package, extract the msi file contained into it,
4 | then run
5 |
6 | checksum.exe {{.Choco.MsiFile}} -t=sha256
7 |
8 | The result must match
9 |
10 | {{.Choco.MsiSum | upper}}
11 |
--------------------------------------------------------------------------------
/templates/choco/chocolateyInstall.ps1:
--------------------------------------------------------------------------------
1 | $packageName = '{{.Choco.ID}}'
2 | $fileType = 'msi'
3 | $silentArgs = '/quiet';
4 | $scriptPath = $(Split-Path $MyInvocation.MyCommand.Path);
5 | $fileFullPath = Join-Path $scriptPath '{{.Choco.MsiFile}}';
6 |
7 | Install-ChocolateyInstallPackage $packageName $fileType $silentArgs $fileFullPath -checksum '{{.Choco.MsiSum}}' -checksumType = 'sha256'
8 |
--------------------------------------------------------------------------------
/templates/choco/chocolateyUninstall.ps1:
--------------------------------------------------------------------------------
1 | $packageName = "{{.Choco.ID}}";
2 | $fileType = 'msi';
3 | $scriptPath = $(Split-Path $MyInvocation.MyCommand.Path);
4 | $fileFullPath = Join-Path $scriptPath '{{.Choco.MsiFile}}';
5 |
6 | Uninstall-ChocolateyPackage $packageName $fileType "$fileFullPath /q"
7 |
--------------------------------------------------------------------------------
/templates/choco/pkg.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{.Choco.ID}}
5 | {{.Choco.Title}}
6 | {{.VersionOk}}
7 | {{.Choco.Authors}}
8 | {{.Choco.Owners}}
9 | {{.Choco.Description}}
10 | {{if gt (.Choco.ProjectURL | len) 0}}
11 | {{.Choco.ProjectURL}}
12 | {{end}}
13 | {{if gt (.Choco.Tags | len) 0}}
14 | {{.Choco.Tags}}
15 | {{end}}
16 | {{if gt (.Choco.LicenseURL | len) 0}}
17 | {{.Choco.LicenseURL}}
18 | {{end}}
19 | {{if gt (.Choco.IconURL | len) 0}}
20 | {{.Choco.IconURL}}
21 | {{end}}
22 | {{if gt (.Choco.ChangeLog | len) 0}}
23 | {{.Choco.ChangeLog}}
24 | {{end}}
25 | {{if .Choco.RequireLicense}}
26 | true
27 | {{else}}
28 | false
29 | {{end}}
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/templates/product.wxs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
27 |
28 | NOT NEWERVERSIONDETECTED
29 |
30 |
31 |
32 |
33 |
34 | {{if gt (.Files.Items | len) 0}}
35 |
36 | {{range $i, $e := .Files.Items}}
37 |
38 | {{end}}
39 |
40 | {{end}}
41 | {{if gt (.Directories | len) 0}}
42 | {{range $i, $e := .Directories}}
43 |
44 | {{end}}
45 | {{end}}
46 |
47 |
48 |
49 | {{if gt (.Env.Vars | len) 0}}
50 |
51 | {{range $i, $e := .Env.Vars}}
52 |
59 | {{end}}
60 |
61 | {{end}}
62 |
63 | {{if gt (.Shortcuts.Items | len) 0}}
64 |
90 | {{end}}
91 |
92 |
93 |
94 | {{range $i, $e := .InstallHooks}}
95 |
96 |
97 | {{end}}
98 | {{range $i, $e := .UninstallHooks}}
99 |
100 |
101 | {{end}}
102 |
103 |
104 | {{range $i, $e := .InstallHooks}}
105 | NOT Installed AND NOT REMOVE
106 | {{end}}
107 | {{range $i, $e := .UninstallHooks}}
108 | REMOVE ~= "ALL"
109 | {{end}}
110 |
111 |
112 |
113 | {{if gt (.Env.Vars | len) 0}}
114 |
115 | {{end}}
116 | {{if gt (.Files.Items | len) 0}}
117 |
118 | {{end}}
119 | {{if gt (.Shortcuts.Items | len) 0}}
120 |
121 | {{end}}
122 | {{range $i, $e := .Directories}}
123 |
124 | {{end}}
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/testing/README.md:
--------------------------------------------------------------------------------
1 | # e2e testing - go-msi
2 |
3 | manual end-to-end testing, fedora box,
4 |
5 | ```sh
6 | sh vagrant-setup.sh
7 |
8 | # to re run as many times as needed to work
9 | sh vagrant-test.sh
10 |
11 | sh vagrant-off.sh
12 |
13 | ```
14 |
15 |
16 |
17 | It does
18 |
19 | - wake up a windows server 2012 box
20 | - setup GO
21 | - setup wix
22 | - setup chocolatey
23 | - prepare a go package of hello/
24 | - invoke testing/main.go
25 | - builds hello.go
26 | - builds an msi
27 | - runs msi /i
28 | - realize some checks that the app installed and works properly
29 | - runs msi /x (uninstall)
30 | - realize some checks
31 | - runs chocolatey packaging
32 | - installs the choco package
33 | - realize some checks that the app installed and works properly
34 | - runs choco remove
35 | - realize some checks
36 | - shut down vagrant
37 | - destroy the box
38 |
--------------------------------------------------------------------------------
/testing/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | Vagrant.configure("2") do |config|
5 |
6 | # on fedora-like, you must use the downloadable package of vagrant
7 | # available on hashi corp website.
8 | # The per distrib provided package wont provide winrm support..
9 | # see https://www.vagrantup.com/downloads.html
10 |
11 | config.vm.define :win2012 do |win|
12 | win.vm.box = "opentable/win-2012r2-standard-amd64-nocm"
13 | # big timeout since windows boot is very slow
14 | win.vm.boot_timeout = 500
15 | win.vm.communicator = :winrm
16 | win.vm.provider "virtualbox" do |vb|
17 | # first setup requires gui to be enabled so scripts can be executed in virtualbox guest screen
18 | vb.gui = false
19 | vb.gui = true
20 | vb.customize ["modifyvm", :id, "--memory", "1024"]
21 | vb.customize ["modifyvm", :id, "--vram", "128"]
22 | vb.customize ["modifyvm", :id, "--cpus", "1"]
23 | vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
24 | vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
25 | vb.customize ["guestproperty", "set", :id, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", 10000]
26 | end
27 |
28 | # config.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".git/"
29 |
30 | end
31 |
32 | end
33 |
--------------------------------------------------------------------------------
/testing/glide.lock:
--------------------------------------------------------------------------------
1 | hash: 7c8e01308dcc94b234a32bc906eb4471d88cac5e33b35ad5017f8ca7514f7197
2 | updated: 2017-03-06T20:54:03.564228552+01:00
3 | imports:
4 | - name: golang.org/x/sys
5 | version: e48874b42435b4347fc52bdee0424a52abc974d7
6 | subpackages:
7 | - windows/svc
8 | testImports: []
9 |
--------------------------------------------------------------------------------
/testing/glide.yaml:
--------------------------------------------------------------------------------
1 | package: github.com/mh-cbon/go-msi/testing
2 | import:
3 | - package: golang.org/x/sys
4 | subpackages:
5 | - windows/svc
6 |
--------------------------------------------------------------------------------
/testing/hello/LICENSE:
--------------------------------------------------------------------------------
1 | This is the license.
2 |
--------------------------------------------------------------------------------
/testing/hello/README.md:
--------------------------------------------------------------------------------
1 | # demo - go-msi
2 |
3 | A demo program for end-to-end testing.
4 |
5 | Find the test suite method [here](https://github.com/mh-cbon/go-msi/tree/master/testing)
6 |
--------------------------------------------------------------------------------
/testing/hello/assets/dir1/file2:
--------------------------------------------------------------------------------
1 | file2
2 |
--------------------------------------------------------------------------------
/testing/hello/assets/file1:
--------------------------------------------------------------------------------
1 | file1
2 |
--------------------------------------------------------------------------------
/testing/hello/change.log:
--------------------------------------------------------------------------------
1 |
2 | 0.0.1
3 |
4 | * A dummy
5 | changelog
6 | * for testing \
7 | purpose
8 |
9 | - mh-cbon
10 |
11 | -- mh-cbon ; Sat, 23 Jul 2016 15:34:40 +0200
12 |
--------------------------------------------------------------------------------
/testing/hello/glide.lock:
--------------------------------------------------------------------------------
1 | hash: fbbc7e2b50d047de95fa2ac0f70ad85818fbb845822855ef2f6f401d1aff4f59
2 | updated: 2017-03-07T14:20:06.739944837+01:00
3 | imports:
4 | - name: github.com/kardianos/osext
5 | version: 9b883c5eb462dd5cb1b0a7a104fe86bc6b9bd391
6 | - name: github.com/kardianos/service
7 | version: ef06f2f890aa4f20d1ff55da91b29392ba6af3af
8 | - name: golang.org/x/sys
9 | version: e48874b42435b4347fc52bdee0424a52abc974d7
10 | subpackages:
11 | - windows
12 | - windows/registry
13 | - windows/svc
14 | - windows/svc/eventlog
15 | - windows/svc/mgr
16 | testImports: []
17 |
--------------------------------------------------------------------------------
/testing/hello/glide.yaml:
--------------------------------------------------------------------------------
1 | package: github.com/mh-cbon/go-msi/testing/hello
2 | import:
3 | - package: github.com/kardianos/service
4 | - package: golang.org/x/sys
5 | subpackages:
6 | - windows/svc/mgr
7 |
--------------------------------------------------------------------------------
/testing/hello/hello.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "log"
7 | "net/http"
8 |
9 | "github.com/kardianos/service"
10 | )
11 |
12 | var logger service.Logger
13 |
14 | func main() {
15 | svcConfig := &service.Config{
16 | Name: "HelloSvc",
17 | DisplayName: "The Hello service",
18 | Description: "This is an example Go service.",
19 | }
20 | runAsService(svcConfig, func() {
21 | fmt.Println("Starting....")
22 | http.HandleFunc("/", handleIndex)
23 | log.Fatal(http.ListenAndServe(":8080", nil))
24 | })
25 | }
26 |
27 | func handleIndex(w http.ResponseWriter, r *http.Request) {
28 | io.WriteString(w, "hello, world\n")
29 | }
30 |
31 | func runAsService(svcConfig *service.Config, run func()) error {
32 | s, err := service.New(&program{exec: run}, svcConfig)
33 | if err != nil {
34 | return err
35 | }
36 | logger, err = s.Logger(nil)
37 | if err != nil {
38 | return err
39 | }
40 | return s.Run()
41 | }
42 |
43 | type program struct {
44 | exec func()
45 | }
46 |
47 | func (p *program) Start(s service.Service) error {
48 | // Start should not block. Do the actual work async.
49 | go p.exec()
50 | return nil
51 | }
52 | func (p *program) Stop(s service.Service) error {
53 | // Stop should not block. Return with a few seconds.
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/testing/hello/ico.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mh-cbon/go-msi/9625c3dd3939a01bcd967a6ed5818cf14c3ffd76/testing/hello/ico.ico
--------------------------------------------------------------------------------
/testing/hello/wix.json:
--------------------------------------------------------------------------------
1 | {
2 | "product": "hello",
3 | "company": "mh-cbon",
4 | "license": "LICENSE",
5 | "upgrade-code": "",
6 | "files": {
7 | "guid": "",
8 | "items": [
9 | "build/amd64/hello.exe"
10 | ]
11 | },
12 | "directories": [
13 | "assets"
14 | ],
15 | "env": {
16 | "guid": "",
17 | "vars": [
18 | {
19 | "name": "some",
20 | "value": "value",
21 | "permanent": "no",
22 | "system": "no",
23 | "action": "set",
24 | "part": "last"
25 | }
26 | ]
27 | },
28 | "shortcuts": {
29 | "guid": "",
30 | "items": [
31 | {
32 | "name": "hello",
33 | "description": "hello web server",
34 | "target": "[INSTALLDIR]\\hello.exe",
35 | "wdir": "INSTALLDIR",
36 | "icon":"ico.ico"
37 | }
38 | ]
39 | },
40 | "hooks": [
41 | {"when": "install", "command": "sc.exe create HelloSvc binPath=\"[INSTALLDIR]hello.exe\" type=share start=auto DisplayName=\"Hello!\""},
42 | {"when": "install", "command": "sc.exe start HelloSvc"},
43 | {"when": "uninstall", "command": "sc.exe delete HelloSvc"}
44 | ],
45 | "choco": {
46 | "description": "hello program",
47 | "project-url": "https://github.com/mh-cbon/go-msi/tree/master/testing",
48 | "tags": "hello",
49 | "license-url": "https://github.com/mh-cbon/go-msi/blob/master/LICENSE"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/testing/main.go:
--------------------------------------------------------------------------------
1 | // +build windows
2 |
3 | package main
4 |
5 | import (
6 | "bytes"
7 | "fmt"
8 | "io"
9 | "io/ioutil"
10 | "log"
11 | "net/http"
12 | "os"
13 | "os/exec"
14 | "path/filepath"
15 | "strings"
16 |
17 | "golang.org/x/sys/windows/svc"
18 | "golang.org/x/sys/windows/svc/mgr"
19 | )
20 |
21 | func main() {
22 |
23 | svcName := "HelloSvc"
24 |
25 | confirm(rmFile("log-install.txt"), "install log removal")
26 | confirm(rmFile("log-uninstall.txt"), "uninstall log removal")
27 |
28 | wd := makeDir("c:/gopath/src/github.com/mh-cbon/go-msi/testing/hello")
29 | mustContains(wd, "hello.go")
30 | mustChdir(wd)
31 |
32 | mustEnvEq("$env:some", "")
33 |
34 | mustMkdirAll("build/amd64")
35 | helloBuild := makeCmd("go", "build", "-o", _p("build/amd64/hello.exe"), "hello.go")
36 | mustExec(helloBuild, "hello build failed %v")
37 |
38 | helloPkgSetup := makeCmd("C:/go-msi/go-msi.exe", "set-guid")
39 | mustExec(helloPkgSetup, "hello packaging setup failed %v")
40 |
41 | helloPkg := makeCmd("C:/go-msi/go-msi.exe", "make",
42 | "--msi", "hello.msi",
43 | "--version", "0.0.1",
44 | "--arch", "amd64",
45 | "--keep",
46 | )
47 | mustExec(helloPkg, "hello packaging failed %v")
48 |
49 | resultPackage := makeFile("hello.msi")
50 | mustExists(resultPackage, "Package file is missing %v")
51 |
52 | mustNotHaveWindowsService("HelloSvc")
53 |
54 | helloPackageInstall := makeCmd("msiexec", "/i", "hello.msi", "/q", "/log", "log-install.txt")
55 | mustExec(helloPackageInstall, "hello package install failed %v")
56 | readFile("log-install.txt")
57 | mustSucceed(rmFile("log-install.txt"), "rmfile failed %v")
58 |
59 | // mustShowEnv("$env:path")
60 | // mustEnvEq("$env:some", "value")
61 |
62 | readDir("C:/Program Files/hello")
63 | readDir("C:/Program Files/hello/assets")
64 |
65 | mgr, helloSvc := mustHaveWindowsService(svcName)
66 | mustHaveStartedWindowsService(svcName, helloSvc)
67 |
68 | helloEpURL := "http://localhost:8080/"
69 | // helloExecPath := "C:/Program Files/hello/hello.exe"
70 | // mustExecHello(helloExecPath, helloEpURL)
71 | mustQueryHello(helloEpURL)
72 | // mustStopWindowsService(svcName, helloSvc)
73 | mustSucceed(helloSvc.Close(), "Failed to close the service %v")
74 | mgr.Disconnect()
75 |
76 | helloPackageUninstall := makeCmd("msiexec", "/x", "hello.msi", "/q", "/log", "log-uninstall.txt")
77 | mustExec(helloPackageUninstall, "hello package uninstall failed %v")
78 | readFile("log-uninstall.txt")
79 | mustSucceed(rmFile("log-uninstall.txt"), "rmfile failed %v")
80 |
81 | mustNotHaveWindowsService("HelloSvc")
82 |
83 | // mustShowEnv("$env:path")
84 | // mustEnvEq("$env:some", "")
85 |
86 | helloChocoPkg := makeCmd("C:/go-msi/go-msi.exe", "choco",
87 | "--input", "hello.msi",
88 | "--version", "0.0.1",
89 | "-c", _qp("C:/Program Files/changelog/changelog.exe")+" ghrelease --version 0.0.1",
90 | "--keep",
91 | )
92 | mustExec(helloChocoPkg, "hello choco package make failed %v")
93 |
94 | helloNuPkg := makeFile("hello.0.0.1.nupkg")
95 | mustExists(helloNuPkg, "Chocolatey nupkg file is missing %v")
96 |
97 | mustNotHaveWindowsService("HelloSvc")
98 |
99 | helloChocoInstall := makeCmd("choco", "install", "hello.0.0.1.nupkg", "-y")
100 | mustExec(helloChocoInstall, "hello choco package install failed %v")
101 |
102 | readDir("C:/Program Files/hello")
103 | readDir("C:/Program Files/hello/assets")
104 |
105 | mgr, helloSvc = mustHaveWindowsService(svcName)
106 | mustHaveStartedWindowsService(svcName, helloSvc)
107 | mustSucceed(helloSvc.Close(), "Failed to close the service %v")
108 | mgr.Disconnect()
109 |
110 | // mustShowEnv("$env:path")
111 | // mustEnvEq("$env:some", "value")
112 |
113 | // mustExecHello(helloExecPath, helloEpURL)
114 | mustQueryHello(helloEpURL)
115 | // mustStopWindowsService(svcName, helloSvc)
116 |
117 | helloChocoUninstall := makeCmd("choco", "uninstall", "hello", "-v", "-d", "-y", "--force")
118 | mustExec(helloChocoUninstall, "hello choco package uninstall failed %v")
119 | readFile("C:\\ProgramData\\chocolatey\\logs\\chocolatey.log")
120 |
121 | mustNotHaveWindowsService("HelloSvc")
122 |
123 | // mustShowEnv("$env:path")
124 | // mustEnvEq("$env:some", "")
125 |
126 | }
127 |
128 | func mustHaveWindowsService(n string) (*mgr.Mgr, *mgr.Service) {
129 | mgr, err := mgr.Connect()
130 | mustSucceed(err, "Failed to connect to the service manager %v")
131 | s, err := mgr.OpenService(n)
132 | mustSucceed(err, "Failed to open the service %v")
133 | if s == nil {
134 | mustSucceed(err, "Failed to find the service %v")
135 | }
136 | log.Printf("SUCCESS: Service %q exists\n", n)
137 | return mgr, s
138 | }
139 |
140 | func mustNotHaveWindowsService(n string) bool {
141 | mgr, err := mgr.Connect()
142 | mustSucceed(err, "Failed to connect to the service manager %v")
143 | defer mgr.Disconnect()
144 | s, err := mgr.OpenService(n)
145 | mustNotSucceed(err, "Must fail to open the service %v")
146 | if s == nil {
147 | mustNotSucceed(err, "Must fail to find the service %v")
148 | } else {
149 | defer s.Close()
150 | }
151 | log.Printf("SUCCESS: Service %q does not exist\n", n)
152 | return s == nil
153 | }
154 |
155 | func mustHaveStartedWindowsService(n string, s *mgr.Service) {
156 | status, err := s.Query()
157 | mustSucceed(err, "Failed to query the service status %v")
158 | if status.State != svc.Running {
159 | mustSucceed(fmt.Errorf("Service not started %v", n))
160 | }
161 | log.Printf("SUCCESS: Service %q was started\n", n)
162 | }
163 |
164 | func mustStopWindowsService(n string, s *mgr.Service) {
165 | status, err := s.Control(svc.Stop)
166 | mustSucceed(err, "Failed to control the service status %v")
167 | if status.State != svc.Stopped {
168 | mustSucceed(fmt.Errorf("Service not stopped %v", n))
169 | }
170 | log.Printf("SUCCESS: Service %q was stopped\n", n)
171 | }
172 |
173 | func mustNotSucceed(err error, format ...string) {
174 | if err == nil {
175 | if len(format) > 0 {
176 | err = fmt.Errorf(format[0], err)
177 | }
178 | log.Fatal(err)
179 | }
180 | }
181 |
182 | func mustQueryHello(u string) {
183 | res := getURL(u)
184 | mustExec(res, "HTTP request failed %v")
185 | mustEqStdout(res, "hello, world\n", "Invalid HTTP response got=%q, want=%q")
186 | log.Printf("SUCCESS: Hello service query %q succeed\n", u)
187 | }
188 |
189 | func mustExecHello(p string, u string) {
190 | helloPackageExec := makeCmd(p)
191 | mustStart(helloPackageExec, "hello command failed %v")
192 | mustQueryHello(u)
193 | mustKill(helloPackageExec, "hello was not killed properly %v")
194 | log.Printf("SUCCESS: Hello program exec %q and query %q succeed\n", p, u)
195 | }
196 |
197 | func _qp(s string) string {
198 | return _q(_p(s))
199 | }
200 |
201 | func _q(s string) string {
202 | return "\"" + s + "\""
203 | }
204 |
205 | func _p(s string) string {
206 | return filepath.Clean(s)
207 | }
208 |
209 | func confirm(err error, message string) {
210 | if err == nil {
211 | log.Printf("DONE: %v\n", message)
212 | } else {
213 | log.Printf("NOT-DONE: (%v) %v", err, message)
214 | }
215 | }
216 | func mustSucceed(err error, format ...string) {
217 | if err != nil {
218 | if len(format) > 0 {
219 | err = fmt.Errorf(format[0], err)
220 | }
221 | log.Fatal(err)
222 | }
223 | }
224 | func mustSucceedDetailed(err error, e interface{}, format ...string) {
225 | if x, ok := e.(stdouter); ok {
226 | fmt.Printf("%T:%v\n", x, x.Stdout())
227 | }
228 | if x, ok := e.(stderrer); ok {
229 | fmt.Printf("%T:%v\n", x, x.Stderr())
230 | }
231 | if err != nil {
232 | if len(format) > 0 {
233 | err = fmt.Errorf(format[0], err)
234 | } else {
235 | err = fmt.Errorf("%v", err)
236 | }
237 | log.Fatal(err)
238 | } else {
239 |
240 | }
241 | }
242 | func mustFail(err error, format ...string) {
243 | if err == nil {
244 | msg := "Expected to fail"
245 | if len(format) > 0 {
246 | msg = format[0]
247 | }
248 | log.Fatal(msg)
249 | }
250 | }
251 | func mustShowEnv(e string) {
252 | psShowEnv := makeCmd("PowerShell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", e)
253 | mustExec(psShowEnv, "powershell command failed %v")
254 | log.Printf("showEnv ok %v %q", e, psShowEnv.Stdout())
255 | }
256 | func maybeShowEnv(e string) *cmdExec {
257 | psShowEnv := makeCmd("PowerShell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", e)
258 | warnExec(psShowEnv, "powershell command failed %v")
259 | log.Printf("showEnv ok %v %q", e, psShowEnv.Stdout())
260 | return psShowEnv
261 | }
262 | func mustLookPath(search string) string {
263 | path, err := exec.LookPath(search)
264 | mustSucceed(err, fmt.Sprintf("lookPath failed %q\n%%v", search))
265 | path = filepath.Clean(path)
266 | log.Printf("lookPath ok %v=%q", search, path)
267 | return path
268 | }
269 | func mustChdir(s fmt.Stringer) {
270 | path := filepath.Clean(s.String())
271 | mustSucceed(os.Chdir(path), fmt.Sprintf("chDir failed %q\n%%v", path))
272 | log.Printf("chdir ok %v", path)
273 | }
274 | func mustEnvEq(env string, expect string, format ...string) {
275 | c := maybeShowEnv(env)
276 | got := c.Stdout()
277 | if len(got) > 0 {
278 | got = got[0 : len(got)-2]
279 | }
280 | f := fmt.Sprintf("Env %q is not equal to want=%q, got=%q", env, expect, got)
281 | mustSucceed(isTrue(got == expect, f))
282 | log.Printf("mustEnvEq ok %v=%q", env, expect)
283 | }
284 | func mustContains(path fmt.Stringer, file string) {
285 | s := mustLs(path)
286 | _, ex := s[file]
287 | f := fmt.Sprintf("File %q not found in %q", file, path)
288 | mustSucceed(isTrue(ex, f))
289 | log.Printf("mustContains ok %v %v", path, file)
290 | }
291 | func mustMkdirAll(path string, perm ...os.FileMode) {
292 | if len(perm) == 0 {
293 | perm = []os.FileMode{os.ModePerm}
294 | }
295 | path = filepath.Clean(path)
296 | mustSucceed(os.MkdirAll(path, perm[0]), fmt.Sprintf("mkdirAll failed %q\n%%v", path))
297 | log.Printf("mkdirAll ok %v %v", path, perm)
298 | }
299 | func mustLs(s fmt.Stringer) map[string]os.FileInfo {
300 | ret := make(map[string]os.FileInfo)
301 | path := filepath.Clean(s.String())
302 | files, err := ioutil.ReadDir(path)
303 | mustSucceed(err, fmt.Sprintf("readdir failed %q, err=%%v", s))
304 | for _, f := range files {
305 | ret[f.Name()] = f
306 | }
307 | return ret
308 | }
309 |
310 | type starter interface {
311 | Start() error
312 | }
313 |
314 | func mustStart(e starter, format ...string) {
315 | if len(format) < 1 {
316 | format[0] = "Start err: %v"
317 | }
318 | mustSucceed(e.Start(), format[0])
319 | }
320 |
321 | type waiter interface {
322 | Wait() error
323 | }
324 |
325 | func mustWait(e waiter, format ...string) {
326 | if len(format) < 1 {
327 | format[0] = "Wait err: %v"
328 | }
329 | mustSucceed(e.Wait(), format[0])
330 | }
331 |
332 | type execer interface {
333 | Exec() error
334 | }
335 |
336 | func mustExec(e execer, format ...string) {
337 | if len(format) < 1 {
338 | format[0] = "Exec err: %v"
339 | }
340 | mustSucceedDetailed(e.Exec(), e, format[0])
341 | log.Printf("mustExec success %v", e)
342 | }
343 |
344 | func warnExec(e execer, format ...string) {
345 | if err := e.Exec(); err != nil {
346 | if len(format) < 1 {
347 | format[0] = "Exec err: %v"
348 | }
349 | log.Printf(format[0], err)
350 | }
351 | }
352 |
353 | type killer interface {
354 | Kill() error
355 | }
356 |
357 | func mustKill(e killer, format ...string) {
358 | if len(format) < 1 {
359 | format[0] = "Kill err: %v"
360 | }
361 | mustSucceed(e.Kill(), format[0])
362 | }
363 |
364 | type exister interface {
365 | exists() bool
366 | }
367 |
368 | func mustExists(e exister, format ...string) {
369 | if len(format) < 1 {
370 | format[0] = fmt.Sprintf("mustExists err: %T does not exist %q, got %%v", e, e)
371 | }
372 | mustSucceed(isTrue(e.exists(), format[0]))
373 | }
374 |
375 | func isTrue(b bool, format ...string) error {
376 | if b == false {
377 | if len(format) < 1 {
378 | format[0] = "mustTrue got %v"
379 | }
380 | return fmt.Errorf(format[0], b)
381 | }
382 | return nil
383 | }
384 |
385 | type stderrer interface {
386 | Stderr() string
387 | }
388 |
389 | type stdouter interface {
390 | Stdout() string
391 | }
392 |
393 | func mustEqStdout(e stdouter, expected string, format ...string) {
394 | got := e.Stdout()
395 | if len(format) < 1 {
396 | format[0] = fmt.Sprintf("mustEqStdout failed: output does not match, got=%q, want=%q", got, expected)
397 | }
398 | mustSucceed(isTrue(got == expected), format[0])
399 | }
400 |
401 | func makeFile(f string) *file {
402 | return &file{f}
403 | }
404 |
405 | type file struct {
406 | path string
407 | }
408 |
409 | func (f *file) exists() bool {
410 | if _, err := os.Stat(f.path); os.IsNotExist(err) {
411 | return false
412 | }
413 | return true
414 | }
415 | func (f *file) String() string {
416 | return f.path
417 | }
418 |
419 | func makeDir(f string) *dir {
420 | return &dir{f}
421 | }
422 |
423 | type dir struct {
424 | path string
425 | }
426 |
427 | func (d *dir) exists() bool {
428 | if _, err := os.Stat(d.path); os.IsNotExist(err) {
429 | return false
430 | }
431 | return true
432 | }
433 | func (d *dir) String() string {
434 | return d.path
435 | }
436 |
437 | func getURL(url string) *httpRequest {
438 | return &httpRequest{url: url}
439 | }
440 |
441 | type httpRequest struct {
442 | url string
443 | err error
444 | body string
445 | statusCode int
446 | headers map[string][]string
447 | }
448 |
449 | func (f *httpRequest) String() string {
450 | return f.url
451 | }
452 |
453 | func (f *httpRequest) Stdout() string {
454 | return f.body
455 | }
456 | func (f *httpRequest) Header(name string) []string {
457 | return f.headers[name]
458 | }
459 | func (f *httpRequest) RespondeCode() int {
460 | return f.statusCode
461 | }
462 | func (f *httpRequest) ExitOk() bool {
463 | return f.statusCode == 200
464 | }
465 | func (f *httpRequest) Exec() error {
466 | response, err := http.Get(f.url)
467 | f.headers = response.Header
468 | f.statusCode = response.StatusCode
469 | f.err = err
470 | if f.err == nil {
471 | var b bytes.Buffer
472 | defer response.Body.Close()
473 | _, f.err = io.Copy(&b, response.Body)
474 | if f.err == nil {
475 | f.body = b.String()
476 | }
477 | }
478 | return f.err
479 | }
480 |
481 | type cmdExec struct {
482 | *exec.Cmd
483 | bin string
484 | args []string
485 | startErr error
486 | hasStarted bool
487 | waitErr error
488 | hasWaited bool
489 | stdout *bytes.Buffer
490 | stderr *bytes.Buffer
491 | }
492 |
493 | func (e *cmdExec) String() string {
494 | return e.bin + " " + strings.Join(e.args, " ")
495 | }
496 |
497 | func (e *cmdExec) SetArgs(args []string) error {
498 | if e.hasStarted {
499 | return fmt.Errorf("Cannot set arguments on command already started")
500 | }
501 | if e.hasWaited {
502 | return fmt.Errorf("Cannot set arguments on command already waited")
503 | }
504 | e.args = args
505 | return nil
506 | }
507 |
508 | func (e *cmdExec) Start() error {
509 | if !e.hasStarted {
510 | e.startErr = e.Cmd.Start()
511 | }
512 | e.hasStarted = true
513 | return e.startErr
514 | }
515 | func (e *cmdExec) Wait() error {
516 | if !e.hasWaited {
517 | e.waitErr = e.Cmd.Wait()
518 | }
519 | e.hasWaited = true
520 | return e.waitErr
521 | }
522 | func (e *cmdExec) Exec() error {
523 | if err := e.Start(); err != nil {
524 | return err
525 | }
526 | return e.Wait()
527 | }
528 | func (e *cmdExec) Kill() error {
529 | return e.Process.Kill()
530 | }
531 | func (e *cmdExec) Stdout() string {
532 | if e.hasStarted == false {
533 | log.Fatal("Process must have run")
534 | }
535 | return e.stdout.String()
536 | }
537 | func (e *cmdExec) Stderr() string {
538 | if e.hasStarted == false {
539 | log.Fatal("Process must have run")
540 | }
541 | return e.stderr.String()
542 | }
543 | func (e *cmdExec) ExitOk() bool {
544 | if e.hasWaited == false {
545 | log.Fatal("Process must have run")
546 | }
547 | return e.ProcessState.Exited() && e.ProcessState.Success()
548 | }
549 |
550 | func makeCmd(w string, a ...string) *cmdExec {
551 | log.Printf("makeCmd: %v %v\n", w, a)
552 | cmd := exec.Command(mustLookPath(w), a...)
553 | var stdout bytes.Buffer
554 | var stderr bytes.Buffer
555 | // cmd.Stdout = &stdout
556 | // cmd.Stderr = &stderr
557 | cmd.Stdout = os.Stderr
558 | cmd.Stderr = os.Stderr
559 | return &cmdExec{Cmd: cmd, stdout: &stdout, stderr: &stderr}
560 | }
561 |
562 | func readDir(s string) {
563 | s = filepath.Clean(s)
564 | files, err := ioutil.ReadDir(s)
565 | mustSucceed(err, fmt.Sprintf("readdir failed %q, err=%%v", s))
566 | log.Printf("Content of directory %q\n", s)
567 | for _, f := range files {
568 | log.Printf(" %v\n", f.Name())
569 | }
570 | }
571 |
572 | func readFile(s string) {
573 | s = filepath.Clean(s)
574 | fd, err := os.Open(s)
575 | mustSucceed(err, fmt.Sprintf("readfile failed %q, err=%%v", s))
576 | defer fd.Close()
577 | if fd != nil {
578 | io.Copy(fd, os.Stdout)
579 | }
580 | }
581 |
582 | func rmFile(s string) error {
583 | s = filepath.Clean(s)
584 | return os.Remove(s)
585 | }
586 |
--------------------------------------------------------------------------------
/testing/test.bat:
--------------------------------------------------------------------------------
1 |
2 | cd C:\\gopath\\src\\github.com\\mh-cbon\\go-msi\\testing\\hello
3 |
4 | C:\\go-msi\\go-msi.exe make --msi hello.msi --version 0.0.1 --arch amd64
5 | msiexec /i hello.msi /q
6 |
7 | mkdir wixtemplates
8 | C:\\go-msi\\go-msi.exe generate-templates --out wixtemplates --version 0.0.1
9 |
--------------------------------------------------------------------------------
/testing/vagrant-off.sh:
--------------------------------------------------------------------------------
1 | set -x
2 | set -e
3 |
4 | vagrant halt
5 | vagrant destroy -f win2012
6 |
--------------------------------------------------------------------------------
/testing/vagrant-setup.sh:
--------------------------------------------------------------------------------
1 | set -x
2 | set -e
3 |
4 | # sudo dnf install http://download.virtualbox.org/virtualbox/5.1.18/VirtualBox-5.1-5.1.18_114002_fedora25-1.x86_64.rpm -y
5 | # sudo dnf install kernel-devel -y
6 | # sudo /sbin/vboxconfig # sometime needed.
7 |
8 | # prepare and load vagrant
9 | # vagrant plugin install winrm-fs # seems useless since vagrant 1.9.7
10 | # vagrant plugin install winrm
11 | vagrant up --provider=virtualbox
12 |
13 | # prepare hello program like appveyor
14 | vagrant winrm -c "mkdir c:\\gopath\\src\\github.com\\mh-cbon\\go-msi\\testing\\hello"
15 | vagrant winrm -c 'Copy-Item C:\\vagrant\\hello\\* -destination c:\\gopath\\src\\github.com\\mh-cbon\\go-msi\\testing\\hello\\ -recurse -Force'
16 |
17 | # setup go
18 | VERSION=`curl https://golang.org/VERSION?m=text`
19 | wget https://storage.googleapis.com/golang/$VERSION.windows-amd64.msi
20 | vagrant winrm -c "COPY C:\\vagrant\\$VERSION.windows-amd64.msi C:\\go.msi"
21 | vagrant winrm -c "msiexec.exe /i C:\\go.msi /quiet"
22 | vagrant winrm -c "setx GOPATH C:\\gopath\\"
23 | vagrant winrm -c "ls env:GOPATH"
24 | rm $VERSION.windows-amd64.msi
25 |
26 | # setup changelog
27 | wget https://github.com/mh-cbon/changelog/releases/download/0.0.25/changelog-amd64.msi
28 | vagrant winrm -c "COPY C:\\vagrant\\changelog-amd64.msi C:\\changelog-amd64.msi"
29 | vagrant winrm -c 'cmd.exe /c "msiexec.exe /i C:\\changelog-amd64.msi /quiet"'
30 | rm changelog-amd64.msi
31 |
32 | # setup go-msi
33 | GOOS=windows GOARCH=amd64 go build -o go-msi.exe ../main.go
34 | vagrant winrm -c "mkdir C:\\go-msi\\templates"
35 | cp -r ../templates .
36 | vagrant winrm -c 'Copy-Item C:\\vagrant\\templates\\* -destination C:\\go-msi\\templates\\ -recurse -Force'
37 | rm -fr templates
38 | vagrant winrm -c 'COPY C:\\vagrant\\go-msi.exe C:\\go-msi\\'
39 | rm -fr go-msi.exe
40 |
41 | # quick test/setup
42 | # GOOS=windows GOARCH=amd64 go build -o go-msi.exe ../main.go
43 | # vagrant winrm -c 'COPY C:\\vagrant\\go-msi.exe C:\\go-msi\\'
44 | # rm -fr go-msi.exe
45 | # vagrant winrm -c 'C:\\go-msi\\go-msi.exe check-env'
46 |
47 |
48 | # setup wix
49 | wget -O wix310-binaries.zip http://wixtoolset.org/downloads/v3.10.3.3007/wix310-binaries.zip
50 | unzip wix310-binaries.zip -d wix310
51 | vagrant winrm -c "xcopy /E /I C:\vagrant\wix310 C:\wix310"
52 | vagrant winrm -c "setx PATH \"%PATH%;C:\\wix310\""
53 | rm -fr wix310 wix310*zip
54 |
55 | # setup chocolatey
56 | vagrant winrm -c 'iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex'
57 | vagrant winrm -c 'choco source add -n=mh-cbon -s="https://api.bintray.com/nuget/mh-cbon/choco"'
58 | vagrant winrm -c 'choco install changelog go-msi emd gump gh-api-cli -y'
59 | vagrant winrm -c 'changelog -v'
60 | vagrant winrm -c 'go-msi -v'
61 | vagrant winrm -c 'emd -version'
62 | vagrant winrm -c 'gh-api-cli -v'
63 |
--------------------------------------------------------------------------------
/testing/vagrant-test.sh:
--------------------------------------------------------------------------------
1 | set -x
2 | set -e
3 |
4 |
5 | vagrant winrm -c "mkdir c:\\gopath\\src\\github.com\\mh-cbon\\go-msi\\testing\\hello"
6 | vagrant winrm -c 'Copy-Item C:\\vagrant\\hello\\* -destination c:\\gopath\\src\\github.com\\mh-cbon\\go-msi\\testing\\hello\\ -recurse -Force'
7 |
8 | cp -r ../templates . && \
9 | vagrant winrm -c 'Copy-Item C:\\vagrant\\templates\\* -destination C:\\go-msi\\templates\\ -recurse -Force' && \
10 | rm -fr templates
11 |
12 | GOOS=windows go build -o test.exe main.go \
13 | && echo "----" \
14 | && vagrant winrm -c "C:\\vagrant\\test.exe"
15 |
16 |
17 | # vagrant winrm -c "ls env:some" || echo "ok, expected not found"
18 |
19 | # vagrant winrm -c "\$env:path"
20 |
21 | # vagrant winrm -c "Get-Content -Path \"C:\\ProgramData\\chocolatey\\logs\\chocolatey.log\" -Tail 100"
22 |
23 | # vagrant winrm -c "choco install c:\gopath\src\github.com\mh-cbon\go-msi\testing\hello\hello.0.0.1.nupkg -y"
24 |
25 | # vagrant winrm -c "choco uninstall hello -y"
26 |
27 | # vagrant winrm -c ". C:\Windows\System32\msiexec.exe /i c:\gopath\src\github.com\mh-cbon\go-msi\testing\hello\hello.msi /quiet"
28 |
29 | # vagrant winrm -c ". C:\Windows\System32\msiexec.exe /uninstall c:\gopath\src\github.com\mh-cbon\go-msi\testing\hello\hello.msi /quiet"
30 |
--------------------------------------------------------------------------------
/tpls/index.go:
--------------------------------------------------------------------------------
1 | package tpls
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "io"
7 | "io/ioutil"
8 | "net/http"
9 | "os"
10 | "path/filepath"
11 | "strings"
12 | "text/template"
13 |
14 | "github.com/mattn/go-zglob"
15 | "github.com/mh-cbon/go-msi/manifest"
16 | )
17 |
18 | var funcMap = template.FuncMap{
19 | "dec": func(i int) int {
20 | return i - 1
21 | },
22 | "cat": func(filename string) string {
23 | out, err := ioutil.ReadFile(filename)
24 | if err != nil {
25 | panic(fmt.Errorf("failed to read file %q", filename))
26 | }
27 | return string(out)
28 | },
29 | "download": func(url string) string {
30 | response, err := http.Get(url)
31 | if err != nil {
32 | panic(fmt.Errorf("failed to download url %q", url))
33 | }
34 | defer response.Body.Close()
35 | var b bytes.Buffer
36 | if _, err := io.Copy(&b, response.Body); err != nil {
37 | panic(fmt.Errorf("failed to download url %q", url))
38 | }
39 | return b.String()
40 | },
41 | "upper": strings.ToUpper,
42 | }
43 |
44 | // Find all wxs fies in given directory
45 | func Find(srcDir string, pattern string) ([]string, error) {
46 | glob := filepath.Join(srcDir, pattern)
47 | return zglob.Glob(glob)
48 | }
49 |
50 | // GenerateTemplate generates given src template to out file using given manifest
51 | func GenerateTemplate(wixFile *manifest.WixManifest, src string, out string) error {
52 | tpl, err := template.New("").Funcs(funcMap).ParseFiles(src)
53 | if err != nil {
54 | return err
55 | }
56 |
57 | fileWriter, err := os.Create(out)
58 | if err != nil {
59 | return err
60 | }
61 | defer fileWriter.Close()
62 | err = tpl.ExecuteTemplate(fileWriter, filepath.Base(src), wixFile)
63 | if err != nil {
64 | return err
65 | }
66 | return nil
67 | }
68 |
--------------------------------------------------------------------------------
/unice-recipe.md:
--------------------------------------------------------------------------------
1 | # unix friendly recipe to create msi package
2 |
3 | This is an HOWDOI build an msi package from a non windows machine.
4 |
5 | It s not very difficult, but its time consuming, especially the first time.
6 |
7 | ### Requirements
8 |
9 | - vagrant, get the source from the website, not from your distro or brewer
10 | - virtualbox, afaik the box i use requires it
11 | - at least 20GB space
12 | - some time ahead
13 |
14 | ### Machine setup
15 |
16 | Start by installing vagrant using the sources available [here](https://www.vagrantup.com/downloads.html)
17 |
18 | Install virtualbox from [here](https://www.virtualbox.org/wiki/Linux_Downloads) (I can t remember if the distro packages are fine, let me know if you try it)
19 |
20 | Install the vagrant plugins
21 |
22 | ```sh
23 | vagrant plugin install winrm
24 | vagrant plugin install vagrant-winrm
25 | vagrant plugin install vagrant-vbguest
26 | vagrant plugin install vagrant-share
27 | ```
28 |
29 | Initialize a new windows vagrant box on root of your directory with a content similar to [this one](https://github.com/mh-cbon/go-msi/blob/master/Vagrantfile)
30 |
31 | A that point you should be ready to `up` the machine,
32 |
33 | ```sh
34 | vagrant up
35 | ```
36 |
37 | And get yourself a coffee. At first init it will start to download the vagrant image which is about 14GB.
38 |
39 | Once the machine is up, ensure `winrm` works correctly
40 |
41 | ```sh
42 | vagrant winrm -c "dir C:\\vagrant"
43 | ```
44 |
45 | The command should display your project files.
46 |
47 |
48 | From your local computer, download [wix](http://wixtoolset.org/releases/v3-10-3-3007/) msi package,
49 |
50 | ```sh
51 | wget -O wix310-binaries.zip http://wixtoolset.org/downloads/v3.10.3.3007/wix310-binaries.zip
52 | # or
53 | curl -O http://wixtoolset.org/downloads/v3.10.3.3007/wix310-binaries.zip
54 |
55 | unzip wix310-binaries.zip -d wix310
56 | ```
57 |
58 | Copy `wix310` folder, clean your copy
59 |
60 | ```sh
61 | vagrant winrm -c "xcopy /E /I C:\vagrant\wix310 C:\wix310"
62 | rm -fr wix310
63 | rm -fr wix310-binaries.zip
64 | ```
65 |
66 | Register `wix` bin path to `PATH`
67 |
68 | ```sh
69 | vagrant winrm -c "setx PATH \"%PATH%;C:\\wix310\""
70 | ```
71 |
72 | Confirm its up to date by running this command
73 |
74 | ```sh
75 | vagrant winrm -c "heat.exe -v"
76 | ```
77 |
78 | From your local computer, download [go-msi](https://github.com/mh-cbon/go-msi/releases) msi package,
79 |
80 | ```sh
81 | wget -O go-msi.msi https://github.com/mh-cbon/go-msi/releases/download/0.0.22/go-msi-amd64.msi
82 | # or
83 | curl -O https://github.com/mh-cbon/go-msi/releases/download/0.0.22/go-msi-amd64.msi
84 | ```
85 |
86 | Trigger `go-msi` setup on the remote windows machine,
87 |
88 | ```sh
89 | vagrant winrm -c "msiexec.exe /i C:\\vagrant\\go-msi-amd64.msi /quiet"
90 | ```
91 |
92 | __At that point, the machine is ready__
93 |
94 | Those steps are to reproduce every time you `destroy` the machine.
95 |
96 | If you only `halt` the machine, you can jump to the next section.
97 |
98 | ### Generate the package
99 |
100 | To generate the package, you can run
101 |
102 | ```sh
103 | vagrant winrm -c "cd C:\\vagrant; go-msi make -m go-msi.msi --version 0.0.1 --arch amd64"
104 | ```
105 |
106 | To test install your packages,
107 |
108 | ```sh
109 | vagrant winrm -c "msiexec.exe /i C:\\vagrant\\go-msi-amd64.msi /quiet"
110 | ```
111 |
112 | To uninstall your package,
113 |
114 | ```sh
115 | vagrant winrm -c "msiexec.exe /uninstall C:\\vagrant\\go-msi-amd64.msi /quiet"
116 | ```
117 |
118 | ### Generate a chocolatey package
119 |
120 | Install chocolatey,
121 |
122 | ```sh
123 | vagrant winrm -c 'iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex'
124 | ```
125 |
126 | Generate the choco package,
127 |
128 | ```sh
129 | vagrant winrm -c 'cmd.exe /c "cd C:\\vagrant\\ && go-msi.exe choco --input go-msi-amd64.msi --version 0.0.1"'
130 | ```
131 |
132 | Test install the choco package,
133 |
134 | ```sh
135 | vagrant winrm -c 'cmd.exe /c "cd C:\\vagrant\\ && choco install go-msi.0.0.1.nupkg -y'
136 | ```
137 |
138 | Test uninstall the choco package,
139 |
140 | ```sh
141 | vagrant winrm -c 'cmd.exe /c "cd C:\\vagrant\\ && choco uninstall go-msi -y'
142 | ```
143 |
144 | Push the choco package,
145 |
146 | ```sh
147 | vagrant winrm -c "cmd.exe /c \"cd C:\\vagrant\\ && choco push -k=\"'xxx'\" go-msi.0.0.1.nupkg\""
148 | ```
149 |
150 | Then `halt` the machine.
151 |
152 | The resulting `msi` package will be placed into your project root.
153 |
154 | ### That's it
155 |
156 | I hope it works for you too,
157 |
158 | ~~ Happy Coding
159 |
--------------------------------------------------------------------------------
/util/index.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "crypto/sha256"
5 | "encoding/hex"
6 | "io"
7 | "os"
8 | "os/exec"
9 | "path/filepath"
10 | )
11 |
12 | // GetBinPath Find path of the current binary file on the file system
13 | func GetBinPath() (string, error) {
14 | var err error
15 | wd := ""
16 | if filepath.Base(os.Args[0]) == "main" { // go run ...
17 | wd, err = os.Getwd()
18 | } else {
19 | bin, err2 := exec.LookPath(os.Args[0])
20 | if err2 == nil {
21 | wd = filepath.Dir(bin)
22 | }
23 | }
24 | return wd, err
25 | }
26 |
27 | //CopyFile copy file src to dst.
28 | func CopyFile(dst, src string) error {
29 | s, err := os.Open(src)
30 | if err != nil {
31 | return err
32 | }
33 | defer s.Close()
34 | d, err := os.Create(dst)
35 | if err != nil {
36 | return err
37 | }
38 | if _, err := io.Copy(d, s); err != nil {
39 | d.Close()
40 | return err
41 | }
42 | return d.Close()
43 | }
44 |
45 | //ComputeSha256 computes the sha256 value of a file content.
46 | func ComputeSha256(filepath string) (string, error) {
47 | hasher := sha256.New()
48 | f, err := os.Open(filepath)
49 | if err != nil {
50 | return "", err
51 | }
52 | defer f.Close()
53 | if _, err := io.Copy(hasher, f); err != nil {
54 | return "", err
55 | }
56 | return hex.EncodeToString(hasher.Sum(nil)), nil
57 | }
58 |
59 | //Exec computes the sha256 value of a file content.
60 | func Exec(w string, args ...string) (string, error) {
61 | cmd := exec.Command(w, args...)
62 | out, err := cmd.CombinedOutput()
63 | return string(out), err
64 | }
65 |
--------------------------------------------------------------------------------
/wix.json:
--------------------------------------------------------------------------------
1 | {
2 | "product": "go-msi",
3 | "company": "mh-cbon",
4 | "license": "LICENSE",
5 | "upgrade-code": "8615055C-D8E0-404C-93BE-441C503BA6F0",
6 | "files": {
7 | "guid": "378896D8-6749-4821-870A-44CBBB791D0C",
8 | "items": [
9 | "go-msi.exe"
10 | ]
11 | },
12 | "directories": [
13 | "templates"
14 | ],
15 | "env": {
16 | "guid": "0CB88C7F-85A7-4986-B6CE-1CAD5C17EA0E",
17 | "vars": [
18 | {
19 | "name": "PATH",
20 | "value": "[INSTALLDIR]",
21 | "permanent": "no",
22 | "system": "no",
23 | "action": "set",
24 | "part": "last"
25 | }
26 | ]
27 | },
28 | "shortcuts": {
29 | "guid": "6DAFD205-3D2D-43D7-BF78-33BFE8746D2A",
30 | "items": [
31 | {
32 | "name": "go-msi",
33 | "description": "Easy msi pakage for Go",
34 | "target": "[INSTALLDIR]\\go-msi.exe",
35 | "wdir": "INSTALLDIR",
36 | "arguments": ""
37 | }
38 | ]
39 | },
40 | "choco": {
41 | "description": "Easy way to generate msi package for a Go project",
42 | "project-url": "https://github.com/mh-cbon/go-msi",
43 | "tags": "generate go msi nuget",
44 | "license-url": "https://github.com/mh-cbon/go-msi/blob/master/LICENSE"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/wix/index.go:
--------------------------------------------------------------------------------
1 | package wix
2 |
3 | import (
4 | "path/filepath"
5 | "strconv"
6 | "strings"
7 |
8 | "github.com/mh-cbon/go-msi/manifest"
9 | )
10 |
11 | var eol = "\r\n"
12 |
13 | // GenerateCmd generates required command lines to produce an msi package,
14 | func GenerateCmd(wixFile *manifest.WixManifest, templates []string, msiOutFile string, arch string) string {
15 |
16 | cmd := ""
17 |
18 | for i, dir := range wixFile.RelDirs {
19 | sI := strconv.Itoa(i)
20 | cmd += "heat dir " + dir + " -nologo -cg AppFiles" + sI
21 | cmd += " -gg -g1 -srd -sfrag -template fragment -dr APPDIR" + sI
22 | cmd += " -var var.SourceDir" + sI
23 | cmd += " -out AppFiles" + sI + ".wxs"
24 | cmd += eol
25 | }
26 | cmd += "candle"
27 | if arch != "" {
28 | if arch == "386" {
29 | arch = "x86"
30 | } else if arch == "amd64" {
31 | arch = "x64"
32 | }
33 | cmd += " -arch " + arch
34 | }
35 | for i, dir := range wixFile.RelDirs {
36 | sI := strconv.Itoa(i)
37 | cmd += " -dSourceDir" + sI + "=" + dir
38 | }
39 | for i := range wixFile.Directories {
40 | sI := strconv.Itoa(i)
41 | cmd += " AppFiles" + sI + ".wxs"
42 | }
43 | for _, tpl := range templates {
44 | cmd += " " + filepath.Base(tpl)
45 | }
46 | cmd += eol
47 | cmd += "light -ext WixUIExtension -ext WixUtilExtension -sacl -spdb "
48 | cmd += " -out " + msiOutFile
49 | for i := range wixFile.Directories {
50 | sI := strconv.Itoa(i)
51 | cmd += " AppFiles" + sI + ".wixobj"
52 | }
53 | for _, tpl := range templates {
54 | cmd += " " + strings.Replace(filepath.Base(tpl), ".wxs", ".wixobj", -1)
55 | }
56 | cmd += eol
57 |
58 | return cmd
59 | }
60 |
--------------------------------------------------------------------------------