diff --git a/cmd/android-project/LICENSE b/cmd/android-project/LICENSE new file mode 100644 index 0000000..ef79069 --- /dev/null +++ b/cmd/android-project/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright © 2017 Maxim Kupriianov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/cmd/android-project/Makefile b/cmd/android-project/Makefile new file mode 100644 index 0000000..f807cbe --- /dev/null +++ b/cmd/android-project/Makefile @@ -0,0 +1,2 @@ +all: + go-bindata -pkg main templates/ diff --git a/cmd/android-project/README.md b/cmd/android-project/README.md new file mode 100644 index 0000000..51a50eb --- /dev/null +++ b/cmd/android-project/README.md @@ -0,0 +1,62 @@ +## android-project + +Android Project tool is a simple replacement for infamous `android` util from Android SDK, prior to Android SDK Tools [Revision 25.3.0 (March 2017) release](https://developer.android.com/studio/releases/sdk-tools.html) when they dropped that util abruptly. Realising their mistake later that March, they got it back, so it actually forwards the commands for `avd`, `target`, and `device` to the underlying layers properly, but still lacks of `android project update` capability. + +I used `android project update` to simply create Ant build scripts for the projects with guarantees, that platform exists and is supported. So this tool does the same thing and it's the only feature implemented now. + +### Installation + +``` +go get github.com/xlab/android-go/cmd/android-project +``` + +Also you must set `$ANDROID_HOME` to your Android SDK location, e.g. + +``` +export ANDROID_HOME=/Users/xlab/Library/Android/sdk +``` + +### Usage + +``` +Usage: android-project update [--sdk] [--target] --name --path + +Updates an Android project (must already have an AndroidManifest.xml) +``` + +[GolangExample](https://github.com/xlab/android-go/blob/master/example/android/Makefile) + +``` +$ android-project update --target android-23 --name GolangExample --path . +. +├── Environment +│   ├── [/Users/xlab/Library/Android/sdk] Android SDK location +│   ├── [/Users/xlab/Library/Android/sdk/ndk-bundle] Android NDK location +│   ├── [/Users/xlab/Library/Android/sdk/platforms] Android Platforms location +│   └── [[android-23 android-N]] Android Platforms available +├── Project +│   ├── [GolangExample] Project name +│   ├── [android-23] Project target +│   └── [.] Project location +└── Files updated + ├── build.xml + ├── local.properties + ├── project.properties + └── proguard-project.txt +``` + +As you can see, the effect of running this command is very similar to `android project update`. At least is used to be. + +``` +$ android project update +************************************************************************* +The "android" command is deprecated. +For manual SDK, AVD, and project management, please use Android Studio. +For command-line tools, use tools/bin/sdkmanager and tools/bin/avdmanager +************************************************************************* +Invalid or unsupported command "project update" +``` + +### License + +MIT diff --git a/cmd/android-project/bindata.go b/cmd/android-project/bindata.go new file mode 100644 index 0000000..9c356d6 --- /dev/null +++ b/cmd/android-project/bindata.go @@ -0,0 +1,306 @@ +// Code generated by go-bindata. +// sources: +// templates/build.xml.tpl +// templates/local.properties.tpl +// templates/proguard-project.txt.tpl +// templates/project.properties.tpl +// DO NOT EDIT! + +package main + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +type asset struct { + bytes []byte + info os.FileInfo +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _templatesBuildXmlTpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xcc\x57\x4f\x6f\x1b\xb7\x13\xbd\xfb\x53\xcc\x6f\x11\x40\x89\x21\xad\x7e\xb9\x15\x86\xe5\xc0\x88\x13\xc4\x68\x63\x07\x89\xdb\x6b\x40\x91\x23\x89\x15\x97\xb3\x25\xb9\x92\x55\xc3\xdf\xbd\x18\x72\xff\x4b\x4e\xdb\x5b\xf7\x62\x63\x97\x1c\xbe\x19\xbe\xf7\x66\x74\xf9\xee\xb1\x30\xb0\x43\xe7\x35\xd9\x45\xf6\x36\xff\x7f\x06\x68\x25\x29\x6d\xd7\x8b\xec\xd7\x87\x8f\xb3\x9f\xb2\x77\x57\x67\x97\xa5\xa3\xdf\x51\x06\xb0\xa2\xc0\x45\xf6\xf4\x94\x7f\x49\x2f\xee\x44\x81\xcf\xcf\x19\x28\x5c\x89\xca\x84\x45\xb6\x41\x53\x66\x57\x67\x67\x00\x00\x97\xff\x9b\xcd\xe0\x61\x83\x60\x48\x0a\x93\x97\x8e\x4a\x74\x41\xa3\x87\x95\x36\x08\xda\x83\x74\x28\x02\x2a\x10\x56\x41\x55\xaa\xf8\xff\xf2\x00\x61\x83\x30\x11\x56\x39\xd2\x6a\x02\x81\xc8\xe4\x31\x60\x7c\x6e\x03\x48\xb2\x41\x68\xeb\xe3\xc2\x52\x84\x0d\x04\x8a\xff\x7f\xbb\xf9\x39\xe7\x05\x7e\x43\x95\x51\x70\x7e\x77\xff\x70\x0e\x4b\x04\xb9\x41\xb9\x45\x05\xda\x06\xea\x22\xfd\x96\xd2\x86\xf7\x64\x83\x23\x03\xdf\x0e\x3e\x60\xe1\x73\x98\xcd\xae\x52\x02\x35\xe4\x43\x04\xbc\xc8\xc6\x79\x64\x30\x1f\xa7\x2a\x6c\x38\x4a\x54\x0a\x1b\x41\xd4\xc9\x2e\x0f\x70\xa0\x2a\xe2\xd4\x1e\xc8\x9a\x03\xa0\xd2\x5d\xea\x1d\xc0\x61\x0d\x38\x49\xa1\x14\xf4\xc2\x07\x02\x1d\x7a\xb5\x79\xd8\x68\xcf\x41\x63\x5d\x8c\x90\xc8\x2b\xe4\x46\xd8\x35\x82\xa7\x02\xe1\xda\x06\xf0\x25\x4a\xbd\xd2\x12\x96\x95\x36\xfd\x70\xbd\x40\x9f\xd0\x21\x08\x57\xef\xea\x9d\x78\xa0\x0a\x0a\x71\x80\xbd\xb0\xa1\x0b\x3e\x4f\x97\x77\x71\xd6\x45\xf0\x54\x39\x89\xb9\xd2\xae\x7b\x97\x20\x62\x64\x11\xd0\x2a\xc2\x4c\xeb\x40\x69\x87\x32\x90\x3b\xe4\x70\x93\xb8\xc4\x79\x4c\xbc\x93\x93\x1e\x2c\xaa\xc2\xdf\x47\xa4\x2a\x94\x55\x78\x29\xe2\x52\xdb\x49\xde\xc3\xf9\x91\x1c\x50\xd8\xa0\x03\xda\xa1\x73\x5a\x89\xa5\xe9\x67\x3c\x05\x43\xb4\x05\x11\x62\xec\x25\xae\xb5\xb5\xda\xae\x9b\xc3\x5c\x65\xd0\x77\xd1\xf8\xbe\x3d\x68\xdb\xb0\x71\x1a\x37\x12\x19\x3f\x17\x36\xcc\x63\xc5\xf3\xc7\xc2\xf4\x00\x7c\xe9\x8a\xeb\xd0\x44\x86\x74\x6c\x8e\xd2\x09\x4c\x52\x72\xe9\x56\x6b\x21\x06\xe1\xd6\xd8\x10\xbd\x0b\xb6\xc4\x56\x47\x95\x67\x98\xc7\x52\x82\xbd\x66\xc1\xf0\xfb\xb4\x74\x02\x42\xf2\x11\xfd\xaa\x44\x22\x35\x2a\x15\x96\x85\x83\x6b\x27\x0c\x94\xc2\x85\x26\xf7\xc4\x1f\x1f\x55\x03\x2b\x72\x4c\x8e\xde\xdd\x88\xb2\x34\xba\x46\xcf\x02\xaf\x45\x39\x92\xe3\x8b\x2a\xec\xa1\x79\x49\x8f\x43\xb1\x8d\xd4\xa8\x57\xe0\xd5\x96\xe9\x02\x7b\xe1\xc1\x52\x00\x8f\x01\x56\x8e\x0a\x20\xdb\xb2\x65\x10\x72\xca\xaf\x6c\x77\x30\x97\x58\xd7\x7b\x78\xf1\xf5\xdd\xcd\xd7\xfb\xdb\x9b\xef\x9f\xee\x3f\x7f\x00\xb4\x3b\xd8\x09\x37\x96\x5f\x51\xf9\xc0\x49\x2a\x3e\x64\x89\x2b\x72\x08\x7b\xf6\x40\xa1\x9a\xdb\xeb\x3b\x84\xd7\x56\xf6\x24\x5f\x43\x5a\x57\xc2\x29\xf6\xb9\x95\x5e\x47\xff\xa8\x3c\xb6\xe9\x1c\x97\x03\xed\x4e\x3b\xb2\x05\xda\xb0\xc8\xd0\xee\x62\x29\xe2\x12\x49\x56\xe9\x78\x05\xcd\xe2\x45\x56\xc7\xc9\x60\x27\x4c\x85\x8b\xec\xd5\x13\xda\x5d\xde\xcf\xed\x39\xbb\x6a\x21\x5d\x6a\xcf\x75\xeb\xb6\x8f\x17\x77\x87\xcd\xdb\xd3\xc6\xb6\x78\x22\xf1\x7f\xd3\x03\x7a\xf5\x21\x32\x53\x10\x1e\xf6\x68\x0c\xff\xbd\xbe\x79\x38\x22\x6e\xdb\x1f\x1a\xb5\xb4\x96\xd7\x2f\x7c\x25\x37\x1c\x60\xa8\xa8\x69\xc4\x61\xf4\xd2\x09\x77\xe8\xc2\x2a\x2c\xd1\x2a\xb4\x92\x6d\x12\x7e\xa1\x3d\x3a\x30\xb8\x43\x73\x64\xa2\xc9\x35\x03\xb9\xc8\xef\x51\x3f\xe8\x02\xbe\x26\xc7\x9f\x73\x69\x84\xf7\xb1\x85\xb1\x80\x3e\x48\xa3\x4b\xdf\x96\xcb\xbf\xf9\x8f\x69\xb2\xa3\x1e\xd3\xb9\x5f\x4c\x27\x3f\x46\x49\x1e\x5f\xf4\x48\x96\x7f\x54\x5a\x6e\xd3\x69\x40\xf6\x98\xd3\x2b\xa1\xcd\xc0\xdf\x0b\xf4\x5e\xac\xb1\xa5\x2d\x67\x5f\x68\xcf\xee\x96\xc3\x67\xb1\x45\xf0\x95\x8b\x8d\x6e\x8d\x16\x9d\x08\x27\xe6\x8d\xe4\x85\x0d\x9d\x6a\x9a\x35\x55\x9e\x44\x6f\x25\xd0\x36\xf2\x40\xb3\xd3\x3b\xaa\xd6\x9b\x93\x92\x6f\x74\xc6\xd2\xd7\xdc\x2b\xf2\x6c\x00\xb7\xb2\x06\xbd\xef\x44\x16\x3f\xf6\x2b\xd0\xae\xbe\x2d\x4a\x72\x01\x4a\x74\x2d\x07\x65\xe5\x03\x15\xf5\x25\xc6\xd6\xc2\x36\x56\x3a\xf4\x7c\x62\xdd\x83\x1c\x51\xe8\xb9\x57\x2c\xf7\xd9\x80\x24\xe3\x09\x80\xdb\x61\x1d\x9a\x49\xe3\x0a\x54\x5a\xb8\x43\x4d\xf9\x56\x0a\x17\x83\x44\x66\xa5\xc3\x59\x44\x72\xfc\x5a\x52\x51\x6a\x83\xa3\x0f\xe4\x43\xf3\x05\x5e\xb7\x40\x0e\xa5\x96\xc2\x98\x03\x5b\x98\x8a\x94\x94\xa4\x10\x68\xb9\xaa\x7c\x62\x62\x3e\xec\xe7\xc3\xe7\x7d\x0a\xa8\xd2\xae\xa6\x1d\x5e\xc0\xab\x27\x1e\x06\xa2\x7c\xd0\xe7\x62\xe9\xc9\x54\x21\xce\x1b\xcf\x3f\x0a\x77\xcb\x75\x4b\xc8\xb8\x23\x44\x93\xd6\x36\x95\x6a\xda\x8c\x00\x58\x47\x57\xf8\x98\x6b\x5b\x56\x61\x18\xff\xcd\x89\xbc\x4b\x21\xb7\x62\x7d\xaa\x22\x2f\x95\xd0\xa0\x48\x9d\xa6\xa5\xbe\x4e\x84\x48\xbd\x2d\xdd\xd7\xf7\x48\x02\x9e\x18\x32\xa0\x92\x33\x17\x66\x91\x05\x57\xe1\x48\x56\x35\x99\xf8\xda\x85\x0c\x95\x68\x8c\x89\x83\x0d\x4c\x84\x6a\x26\xe8\x3f\x11\xf0\x51\xfb\x10\xa7\x84\x44\x84\xd8\xfe\xea\xc1\x2f\xec\xa9\x3e\xb1\xcf\x8b\x19\xbc\x6f\x77\xc7\xc9\x95\xeb\x97\x76\x0f\xd9\x03\x33\x90\x54\x1e\xe6\xa5\xf0\x01\x23\xac\x7a\x62\x89\xfe\x12\x1a\x2b\x9b\xc2\x79\x6a\x91\xe7\xc3\xc9\x37\x3d\x75\x45\xae\x20\x08\xbf\xcd\x8f\xe2\xb7\x48\x74\x1c\x45\xd9\xe9\xc0\x22\xaa\xfe\x20\xdb\x07\xcc\x28\xf6\x1b\xe2\x89\x9c\x6c\x60\x45\xd1\x0a\xba\x91\xec\xc7\xf0\x7b\x5b\xda\xb9\xaf\x1e\xf7\x5e\x17\xda\x56\x49\x72\x81\x4a\xb0\xa4\xf0\xcd\x38\x95\x71\xda\x0e\x99\x72\xcd\x84\xf6\x4f\x13\x1d\x65\xd9\x2d\x3c\x3f\xfd\x8c\x17\xc0\xed\xe7\x2f\xf7\x5f\x1f\xae\xef\x1e\xe0\xf4\x82\x1f\x44\xb8\xb5\x20\x8c\x01\x29\x7c\xf3\x33\x80\x07\x9d\xda\x4a\x39\x89\x38\x4d\x70\x7d\xea\x9f\x93\xb3\x20\xd6\xb0\x44\x43\x7b\xc6\xed\x50\x28\x98\xa4\x54\x26\xa0\xad\x0f\xfc\x82\x56\x6d\x27\x43\x37\x3d\xeb\x95\x0b\xc8\x29\x8c\xbe\x2c\x76\xec\xd9\x1b\xb1\xe3\x6a\xc5\xf4\x63\x13\x5c\x62\x23\x57\x85\x36\x4e\x0c\x3c\x66\xb7\x6d\x3d\x3b\x6d\xf6\xd9\x50\x72\x2c\x9d\x1e\xdc\x0b\x78\xfb\x82\x1c\x5f\x3d\xd5\x86\xfe\x3c\x3f\x31\xce\x27\x31\x5e\xce\xeb\x43\xae\xce\xfe\x0a\x00\x00\xff\xff\x41\x1f\xa7\xd1\x58\x0f\x00\x00") + +func templatesBuildXmlTplBytes() ([]byte, error) { + return bindataRead( + _templatesBuildXmlTpl, + "templates/build.xml.tpl", + ) +} + +func templatesBuildXmlTpl() (*asset, error) { + bytes, err := templatesBuildXmlTplBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "templates/build.xml.tpl", size: 3928, mode: os.FileMode(420), modTime: time.Unix(1493565767, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _templatesLocalPropertiesTpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x74\x90\xcd\x6e\xea\x30\x10\x85\xf7\x7e\x8a\x73\x95\x1d\x82\xbc\xc1\x5d\x70\x49\xee\x8f\x40\x20\x11\x6e\xab\x2e\x8d\x3d\x21\x23\x1c\x0f\xf2\x38\xaa\x52\xc4\xbb\x57\x01\xb5\xea\xa6\xdb\xd1\x39\xf3\x7d\x33\x05\x0e\x1d\x2b\x5a\x0e\x04\x56\xd8\x21\x4b\x6f\x33\x3b\x1b\xc2\x88\x13\x45\x4a\x36\x93\xc7\x71\xc4\x32\xfa\x24\xec\x71\x10\x09\x5a\x9a\x02\x95\x20\x4a\x46\x2f\x9e\xdb\x11\xf9\x73\xcd\x62\x81\x97\xdd\xff\x3d\x56\x7f\x97\xdb\x3f\x75\x83\xe7\x7f\x9b\x0d\x7e\xd5\xa8\xf7\xcb\xa6\xae\x7e\x98\xc2\x7c\x85\xf6\x83\x66\xcc\xb6\xbb\xc3\x0c\x47\x82\xeb\xc8\x9d\xc9\x83\x63\x16\x3c\x51\x52\x96\x88\x95\xc4\x9c\x24\xa0\x19\x35\x53\xaf\x73\x53\xc0\x2a\x38\xc3\x49\xcc\x96\xa3\x82\x63\x2b\x69\xf2\x96\x08\xbd\x90\xe3\x96\x1d\xb2\x60\x94\x21\x21\x88\xb3\x61\xca\xb6\x7c\x1a\xd2\x3d\x54\x1a\x53\xdc\xe7\xf7\x86\xb4\xc8\x1d\xa1\xa9\xd6\xe5\x43\x8c\x15\x12\xc3\x88\x41\x3f\x4e\xcf\xa6\xc0\x6f\x49\x70\x83\x66\xe9\xf9\xed\x51\x7c\xed\x28\x62\x50\x8e\x27\xd8\x6f\x6c\xe7\xb8\x04\xb2\x4a\x48\x64\xfd\x84\x31\x05\x3a\xb2\x9e\xd2\xf4\x3c\x2a\x8d\xfa\x73\xe9\x39\xfd\xbc\x5e\xcb\xa6\x5a\x57\x9c\x6e\x37\xf3\x1e\x00\x00\xff\xff\x27\xf5\x2a\x60\x95\x01\x00\x00") + +func templatesLocalPropertiesTplBytes() ([]byte, error) { + return bindataRead( + _templatesLocalPropertiesTpl, + "templates/local.properties.tpl", + ) +} + +func templatesLocalPropertiesTpl() (*asset, error) { + bytes, err := templatesLocalPropertiesTplBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "templates/local.properties.tpl", size: 405, mode: os.FileMode(420), modTime: time.Unix(1493565247, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _templatesProguardProjectTxtTpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x6c\x92\x4f\x6f\xd5\x30\x10\xc4\xef\xf9\x14\x23\x85\x13\x7a\xf5\xbb\x97\x13\x1c\x40\xf4\x84\x54\x04\xe2\xb8\xb1\x37\xc9\xb6\x8e\xed\xfa\xcf\x7b\x44\x55\xbf\x3b\xb2\x93\x14\xf1\xe7\x16\xcb\xb3\x33\xb3\x3f\xa7\xc7\x57\x0f\x76\x34\x58\xc6\x97\xe8\x3f\x15\x8a\x06\xe2\xb0\xfa\x12\x11\xa2\x7f\x60\x9d\x4f\x60\x23\xf9\x38\xa9\x10\x7d\xe0\x98\x85\x53\xd7\x23\x7b\x18\x1e\xc5\x31\xf2\xcc\x55\x32\x55\x07\xa5\xbd\x1b\x65\xc2\x2e\x5d\x41\x09\x86\x93\x8e\x32\x70\xb3\xcf\x33\x65\x8c\x62\x59\x75\x7d\xd7\xe3\xbd\x31\x87\x3d\x52\x60\x2d\xa3\xe8\xdf\x75\x62\xb1\x9c\x30\x73\xac\x6a\x7c\x58\x6b\x22\x15\x9b\x4f\x2d\x73\xb4\x34\xa5\xcd\x53\x52\xf3\x04\x45\x06\x85\xc0\xce\xb0\xa9\x0d\x37\xc9\x6e\xcc\xa6\xeb\xab\xfc\xcd\x73\x32\x8f\xca\x48\x7c\x39\x67\xef\x6d\x3a\x1f\xe5\x5f\x3f\x6e\xc8\x99\xe8\xc5\xa8\xfc\x33\x77\x3d\x7e\xf8\x02\x4d\x6e\x83\x51\x93\xc5\x69\x5b\x0c\x23\x50\x9e\x41\xce\xc0\x47\xc3\x11\xc3\x0a\x3d\x93\x9b\xc4\x4d\x4d\x76\xec\xd1\x62\xf7\x89\x83\x8b\xb8\xff\x60\xdd\x98\x7c\xf4\x11\x8b\x8f\x0c\xc3\x99\xc4\xa6\x13\x12\x73\xd7\x03\x98\x73\x0e\xb7\xe7\xb3\xe1\x0b\xdb\x3a\xa3\x8e\x9e\xda\x2f\xe7\xa9\x88\xe1\xe3\x4e\xdc\xf4\xd7\x72\x6a\xce\x8b\xed\x76\xe4\xe4\xd6\x7f\xb1\x3f\x32\x07\xf8\x90\xc5\xbb\x0d\xfa\x6d\x95\x7f\x1e\xff\xf8\x25\x50\x12\x27\x7c\xe7\xe1\x9b\xf0\x15\x57\xc9\x33\xee\xee\x4f\x28\x4e\xfb\x65\x61\xb7\xf1\x19\xbd\xb5\xfe\x2a\x6e\xea\xfa\x86\x67\x8b\x58\xb7\xbb\x62\xed\x8a\xa7\x42\xb6\x3d\x09\xb4\xa5\x94\xe0\x68\xe1\xfa\x60\x55\x71\x47\x17\xba\xd7\x51\x42\x86\xb8\xcc\x71\x24\x5d\xd7\x6f\xc2\xdb\xae\xbf\xa9\x3d\xdb\x61\xe1\x65\xe0\x98\x76\x8b\xf1\x49\x3b\xe5\x47\xf5\x40\x17\x4a\x6d\x5c\xbd\x8e\xab\xd1\x47\x75\xe5\xe1\x52\x4b\x3f\x37\x96\xa1\x0c\x56\x34\xde\xbe\xeb\xfa\x97\xee\x57\x00\x00\x00\xff\xff\x7b\xb3\x66\x73\x0d\x03\x00\x00") + +func templatesProguardProjectTxtTplBytes() ([]byte, error) { + return bindataRead( + _templatesProguardProjectTxtTpl, + "templates/proguard-project.txt.tpl", + ) +} + +func templatesProguardProjectTxtTpl() (*asset, error) { + bytes, err := templatesProguardProjectTxtTplBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "templates/proguard-project.txt.tpl", size: 781, mode: os.FileMode(420), modTime: time.Unix(1493565270, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _templatesProjectPropertiesTpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x4c\x51\x4d\x8f\xd3\x30\x10\xbd\xfb\x57\x3c\x36\x1c\x40\x6a\xb3\xf7\x4a\x7b\x28\xbb\xd5\x82\xb4\x02\xb4\x2d\x20\x8e\x8e\x3d\x6d\x4c\x13\x4f\x35\x1e\x57\x84\xaa\xff\x1d\x39\x29\x2d\xa7\x8c\x5e\xe6\x7d\x79\x2a\x6c\xda\x90\xb0\x0d\x1d\x21\x24\xd8\xac\xdc\x5b\x0d\xce\x76\xdd\x80\x1d\x45\x12\xab\xe4\xd1\x0c\x58\x46\x2f\x1c\x3c\x36\xcc\x5d\xaa\x4d\x85\x27\x46\x64\x45\xcf\x3e\x6c\x07\xe8\x55\x66\x3e\xc7\xcf\x2f\xdf\x5e\xf1\xf8\x71\xf9\xf9\x79\xb5\xc6\x8f\x4f\x2f\x2f\xf8\xb0\xc2\xea\x75\xb9\x5e\x3d\xbd\x31\x95\xf9\xdf\xb4\xcf\x49\xd1\x10\x5c\x4b\x6e\x4f\x1e\x21\xe2\x3b\x49\x0a\x1c\xf1\xc8\x51\x85\x3b\xac\x87\xa4\xd4\x17\xcf\xc2\x64\xb8\x9c\x94\xfb\xf0\x87\x70\x10\x3e\x90\x68\xa0\x84\x9c\xa6\x98\xda\x12\x96\x51\xd1\xe4\xd0\x79\xa4\x91\x0a\xf2\x41\x4d\x85\x3b\x1b\xb5\xbe\x71\xee\x66\xb0\xd1\x83\x8f\x24\x12\x3c\xe1\x68\xbb\x4c\x09\xca\xb0\xde\x1e\x74\x94\x4a\x4e\x42\x19\x19\x03\x67\x31\x55\xb1\xfc\x45\x4e\x91\x54\xb2\xd3\x2c\x74\x8d\x45\xd1\x36\x1d\xe1\xab\xf0\x73\xb6\xe2\x0b\x27\xb5\x12\xe2\x7e\x72\x69\xb6\x39\x39\xab\x34\x0a\xc1\xb1\xa7\x19\x72\x74\xdc\xf7\x14\x75\x7a\xbe\x77\xf6\x68\x43\x37\xaa\xdc\x52\x2e\x90\xfc\xbe\xf6\x41\x66\xa5\xa3\xd4\x2d\xf7\xf4\x7e\x61\xaa\x83\xf0\xae\xf8\xd4\x8e\xe3\x36\xec\x1e\xde\x9e\x2e\x7b\xe7\x7b\x2d\x27\xba\xff\xb7\x70\x1d\xe6\x76\x3a\x61\xad\xbf\x75\x71\x05\x2f\x85\x0a\x68\x4c\x55\xe2\x8f\xfd\xd4\xca\x8e\xb4\x36\xd3\xf7\xe1\x74\xaa\x2f\x7f\x36\x23\x70\x3e\x9b\xbf\x01\x00\x00\xff\xff\xbb\x01\x89\xe1\x3b\x02\x00\x00") + +func templatesProjectPropertiesTplBytes() ([]byte, error) { + return bindataRead( + _templatesProjectPropertiesTpl, + "templates/project.properties.tpl", + ) +} + +func templatesProjectPropertiesTpl() (*asset, error) { + bytes, err := templatesProjectPropertiesTplBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "templates/project.properties.tpl", size: 571, mode: os.FileMode(420), modTime: time.Unix(1493565298, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, fmt.Errorf("Asset %s not found", name) +} + +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, fmt.Errorf("AssetInfo %s not found", name) +} + +// AssetNames returns the names of the assets. +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// _bindata is a table, holding each asset generator, mapped to its name. +var _bindata = map[string]func() (*asset, error){ + "templates/build.xml.tpl": templatesBuildXmlTpl, + "templates/local.properties.tpl": templatesLocalPropertiesTpl, + "templates/proguard-project.txt.tpl": templatesProguardProjectTxtTpl, + "templates/project.properties.tpl": templatesProjectPropertiesTpl, +} + +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + } + } + if node.Func != nil { + return nil, fmt.Errorf("Asset %s not found", name) + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} +var _bintree = &bintree{nil, map[string]*bintree{ + "templates": &bintree{nil, map[string]*bintree{ + "build.xml.tpl": &bintree{templatesBuildXmlTpl, map[string]*bintree{}}, + "local.properties.tpl": &bintree{templatesLocalPropertiesTpl, map[string]*bintree{}}, + "proguard-project.txt.tpl": &bintree{templatesProguardProjectTxtTpl, map[string]*bintree{}}, + "project.properties.tpl": &bintree{templatesProjectPropertiesTpl, map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) + if err != nil { + return err + } + return nil +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} + diff --git a/cmd/android-project/main.go b/cmd/android-project/main.go new file mode 100644 index 0000000..cec4c96 --- /dev/null +++ b/cmd/android-project/main.go @@ -0,0 +1,152 @@ +package main + +import ( + "log" + "os" + "path/filepath" + + "github.com/jawher/mow.cli" + "github.com/xlab/closer" + "github.com/xlab/treeprint" +) + +var app = cli.App("android-project", `Android project bootstrap tool for use instead of version that was removed from Android SDK (since Revision 25.3.0). + See https://developer.android.com/studio/releases/sdk-tools.html`) + +func init() { + log.SetFlags(0) +} + +func main() { + app.Command("update", "Updates an Android project (must already have an AndroidManifest.xml).", cmdUpdateFunc) + app.Command("platforms", "Lists Android platforms supported within SDK.", cmdPlatformsFunc) + + if err := app.Run(os.Args); err != nil { + closer.Fatalln(err) + } +} + +func cmdPlatformsFunc(c *cli.Cmd) { + sdkDir := c.String(cli.StringOpt{ + Name: "sdk", + Desc: "Android SDK location, can also be set using ANDROID_HOME env variable.", + EnvVar: "ANDROID_HOME", + HideValue: true, + }) + c.Spec = "[--sdk]" + c.Action = func() { + defer closer.Close() + + if len(*sdkDir) == 0 { + closer.Fatalln("ANDROID_HOME environment variable not set (or --sdk flag not provided).") + } + _, platformsDir := learnPaths(*sdkDir) + log.Println("Available Android platforms:") + platforms := learnPlatforms(platformsDir) + for _, platform := range platforms { + log.Println("*", platform) + } + } +} + +func cmdUpdateFunc(c *cli.Cmd) { + pathOpt := c.StringOpt("p path", "", "The project's directory.") + nameOpt := c.StringOpt("n name", "", "Project name.") + forceOpt := c.BoolOpt("f force", false, "Force generation, even if the target platform is not supported.") + targetOpt := c.StringOpt("t target", "android-23", "Target ID to set for the project.") + sdkDir := c.String(cli.StringOpt{ + Name: "sdk", + Desc: "Android SDK location, can also be set using ANDROID_HOME env variable.", + EnvVar: "ANDROID_HOME", + HideValue: true, + }) + c.Spec = "[--sdk] [--target] --name --path" + c.Action = func() { + defer closer.Close() + + if len(*sdkDir) == 0 { + closer.Fatalln("ANDROID_HOME environment variable not set (or --sdk flag not provided).") + } + tree := treeprint.New() + closer.Bind(func() { + log.Println(tree) + }) + ndkDir, platformsDir := learnPaths(*sdkDir) + + env := tree.AddBranch("Environment"). + AddMetaNode(*sdkDir, "Android SDK location"). + AddMetaNode(ndkDir, "Android NDK location"). + AddMetaNode(platformsDir, "Android Platforms location") + platforms := learnPlatforms(platformsDir) + env.AddMetaNode(platforms, "Android Platforms available") + + ctx := &TemplateContext{ + ProjectName: *nameOpt, + ProjectTarget: *targetOpt, + + SDKDir: *sdkDir, + } + tree.AddBranch("Project"). + AddMetaNode(ctx.ProjectName, "Project name"). + AddMetaNode(ctx.ProjectTarget, "Project target"). + AddMetaNode(*pathOpt, "Project location") + + manifestFileName := filepath.Join(*pathOpt, "AndroidManifest.xml") + if _, err := os.Stat(manifestFileName); os.IsNotExist(err) { + closer.Fatalln("AndroidManifest.xml not found in project location") + } + var platformSupported bool + for _, platform := range platforms { + if *targetOpt == platform { + platformSupported = true + } + } + if !platformSupported && !(*forceOpt) { + closer.Fatalln("Platform", *targetOpt, "not supported within this SDK, build may fail. Use -f flag to override.") + } + + files := tree.AddBranch("Files updated") + for _, tpl := range templates { + fileName := filepath.Join(*pathOpt, tpl.TargetName()) + f, err := os.Create(fileName) + if err != nil { + closer.Fatalf("Failed to create file %s: %v", fileName, err) + } + if err := tpl.Render(ctx, f); err != nil { + closer.Fatalf("Failed to render template %s: %v", tpl.Name(), err) + } + f.Close() + files.AddNode(fileName) + } + } +} + +func learnPlatforms(platformsDir string) []string { + var platforms []string + filepath.Walk(platformsDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if path == platformsDir { + return nil + } + platforms = append(platforms, filepath.Base(path)) + return filepath.SkipDir + }) + return platforms +} + +func learnPaths(sdkDir string) (ndkDir, platformsDir string) { + if _, err := os.Stat(sdkDir); err != nil { + closer.Fatalln("Android SDK location is provided but not valid:", sdkDir) + } + ndkDir = filepath.Join(sdkDir, "ndk-bundle") + if _, err := os.Stat(sdkDir); err != nil { + closer.Fatalln("Android SDK location is provided but has no ndk-bundle:", ndkDir) + } + platformsDir = filepath.Join(sdkDir, "platforms") + if _, err := os.Stat(sdkDir); err != nil { + closer.Fatalln("Android SDK location is provided but has no platforms:", platformsDir) + } + return +} diff --git a/cmd/android-project/templates.go b/cmd/android-project/templates.go new file mode 100644 index 0000000..f91e26b --- /dev/null +++ b/cmd/android-project/templates.go @@ -0,0 +1,64 @@ +package main + +import ( + "io" + "text/template" +) + +type TemplateContext struct { + ProjectName string + ProjectTarget string + SDKDir string +} + +type Template interface { + Name() string + TargetName() string + Render(ctx *TemplateContext, wr io.Writer) error +} + +var templates = []Template{ + &tpl{ + name: "build.xml.tpl", + target: "build.xml", + Template: template.Must(template.New("build.xml.tpl"). + Parse(string(MustAsset("templates/build.xml.tpl")))), + }, + &tpl{ + name: "local.properties.tpl", + target: "local.properties", + Template: template.Must(template.New("local.properties.tpl"). + Parse(string(MustAsset("templates/local.properties.tpl")))), + }, + &tpl{ + name: "project.properties.tpl", + target: "project.properties", + Template: template.Must(template.New("project.properties.tpl"). + Parse(string(MustAsset("templates/project.properties.tpl")))), + }, + &tpl{ + name: "proguard-project.txt.tpl", + target: "proguard-project.txt", + Template: template.Must(template.New("proguard-project.txt.tpl"). + Parse(string(MustAsset("templates/proguard-project.txt.tpl")))), + }, +} + +type tpl struct { + *template.Template + + name string + target string +} + +func (t *tpl) Name() string { + return t.name +} + +func (t *tpl) TargetName() string { + return t.target +} + +func (t *tpl) Render(ctx *TemplateContext, wr io.Writer) error { + return t.Template.Execute(wr, ctx) +} diff --git a/cmd/android-project/templates/build.xml.tpl b/cmd/android-project/templates/build.xml.tpl new file mode 100644 index 0000000..83b9d4a --- /dev/null +++ b/cmd/android-project/templates/build.xml.tpl @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmd/android-project/templates/local.properties.tpl b/cmd/android-project/templates/local.properties.tpl new file mode 100644 index 0000000..0008e8d --- /dev/null +++ b/cmd/android-project/templates/local.properties.tpl @@ -0,0 +1,10 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. + +# location of the SDK. This is only used by Ant +# For customization when using a Version Control System, please read the +# header note. +sdk.dir={{.SDKDir}} diff --git a/cmd/android-project/templates/proguard-project.txt.tpl b/cmd/android-project/templates/proguard-project.txt.tpl new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/cmd/android-project/templates/proguard-project.txt.tpl @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/cmd/android-project/templates/project.properties.tpl b/cmd/android-project/templates/project.properties.tpl new file mode 100644 index 0000000..619cb0d --- /dev/null +++ b/cmd/android-project/templates/project.properties.tpl @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target={{.ProjectTarget}}