Skip to content

Commit

Permalink
Add/npm publish (danielpaulus#116)
Browse files Browse the repository at this point in the history
Adds compiling a windows release.
Allows go-ios now to be installed using npm install -g go-ios
on windows, mac and linux computers.
  • Loading branch information
danielpaulus authored Apr 14, 2022
1 parent 684ebc7 commit db84353
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 6 deletions.
73 changes: 67 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ on:
- main
name: Release-Go-iOS
jobs:
build_on_mac:
runs-on: macos-latest
build_on_windows:
runs-on: windows-latest
steps:
- name: Create Release
id: create_release
Expand All @@ -20,15 +20,47 @@ jobs:
go-version: 1.17.x
- name: Checkout code
uses: actions/checkout@v2
- name: Build
run: |
get-content main.go | %{$_ -replace "local-build","${{ steps.create_release.outputs.current_tag }}"}
mkdir bin
go build -ldflags="-s -w" -o bin/ios.exe
"${{ steps.create_release.outputs.current_tag }}" | Out-File -Encoding utf8NoBOM release_tag -NoNewline
Compress-Archive -Path .\bin\ios.exe, release_tag -CompressionLevel Optimal -DestinationPath go-ios-windows.zip
- name: upload the windows build
uses: actions/upload-artifact@v2
with:
name: windows-build
path: go-ios-windows.zip
retention-days: 1
build_on_mac:
runs-on: macos-latest
needs: build_on_windows
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.17.x
- name: Checkout code
uses: actions/checkout@v2
- name: Download win release from previous job
uses: actions/download-artifact@v2
with:
name: windows-build
path: ./win-bin
- name: Extract release tag
run: |
unzip go-ios-windows.zip
echo "release_tag="$(cat release_tag) >> $GITHUB_ENV
working-directory: ./win-bin
- name: Build
run: |
brew install gnu-sed
alias sed=gsed
gsed -i 's/version \= \"local-build\"/version = \"${{ steps.create_release.outputs.current_tag }}\"/' main.go
gsed -i 's/version \= \"local-build\"/version = \"${{ env.release_tag }}\"/' main.go
mkdir bin
go build -ldflags="-s -w" -o bin/ios
echo ${{ steps.create_release.outputs.current_tag }} > release_tag
zip -j go-ios-mac.zip bin/ios release_tag
zip -j go-ios-mac.zip bin/ios
- name: upload the macos build
uses: actions/upload-artifact@v2
with:
Expand All @@ -53,19 +85,48 @@ jobs:
- name: Download and package mac binary
run: |
unzip go-ios-mac.zip
echo "release_tag="$(cat release_tag) >> $GITHUB_ENV
rm go-ios-mac.zip
zip -j go-ios-mac.zip ios
working-directory: ./mac-bin
- name: Download windows release from previous job
uses: actions/download-artifact@v2
with:
name: windows-build
path: ./win-bin
- name: Download and package windows binary
run: |
unzip go-ios-windows.zip
echo "release_tag="$(cat release_tag) >> $GITHUB_ENV
rm go-ios-windows.zip
zip -j go-ios-win.zip ios.exe
working-directory: ./win-bin
- name: Build
run: |
sed -i 's/version \= \"local-build\"/version = \"${{ env.release_tag }}\"/' main.go
mkdir bin
go build -ldflags="-s -w" -o bin/ios
cp ./mac-bin/go-ios-mac.zip .
cp ./win-bin/go-ios-win.zip .
zip -j go-ios-linux.zip bin/ios
- uses: AButler/[email protected]
with:
files: "*.zip"
repo-token: ${{ secrets.GITHUB_TOKEN }}
release-tag: ${{ env.release_tag }}
- name: Publish NPM
run: |
mkdir ./npm_publish/dist
mkdir ./npm_publish/dist/go-ios-darwin-amd64_darwin_amd64
mkdir ./npm_publish/dist/go-ios-linux-amd64_linux_amd64
mkdir ./npm_publish/dist/go-ios-windows-amd64_windows_amd64
cp ./mac-bin/ios ./npm_publish/dist/go-ios-darwin-amd64_darwin_amd64/ios
cp ./win-bin/ios.exe ./npm_publish/dist/go-ios-windows-amd64_windows_amd64/ios
cp ./bin/ios ./npm_publish/dist/go-ios-linux-amd64_linux_amd64/ios
echo "//registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc
cd npm_publish
sed -i 's/\"local-build\"/\"${{ env.release_tag }}\"/' package.json
npm install
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
*.mobileprovision
*.p12
testdata/wda-signed.ipa
Expand Down
31 changes: 31 additions & 0 deletions npm_publish/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "go-ios",
"version": "local-build",
"description": "Provide a stable and production ready opensource solution to automate iOS device on Linux, Windows and Mac OS X.",
"main": "index.js",
"scripts": {
"postinstall": "node postinstall.js install",
"preuninstall": "node postinstall.js uninstall"
},
"repository": {
"type": "git",
"url": "git+https://github.com/danielpaulus/go-ios.git"
},
"author": "Daniel Paulus",
"license": "MIT",
"bugs": {
"url": "https://github.com/danielpaulus/go-ios/issues"
},
"homepage": "https://github.com/danielpaulus/go-ios#readme",
"goBinary": {
"name": "ios",
"path": "./bin"
},
"files": [
"dist",
"postinstall.js"
],
"dependencies": {
"mkdirp": "^1.0.4"
}
}
211 changes: 211 additions & 0 deletions npm_publish/postinstall.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#!/usr/bin/env node

"use strict";
// Thanks to author of https://github.com/sanathkr/go-npm, we were able to modify his code to work with private packages
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var path = require('path'),
mkdirp = require('mkdirp'),
fs = require('fs');

// Mapping from Node's `process.arch` to Golang's `$GOARCH`
var ARCH_MAPPING = {
// "ia32": "386",
"x64": "amd64",
"arm": "arm"
};

// Mapping between Node's `process.platform` to Golang's
var PLATFORM_MAPPING = {
"darwin": "darwin",
"linux": "linux",
"win32": "windows",
"freebsd": "freebsd"
};

async function getInstallationPath() {

// `npm bin` will output the path where binary files should be installed

const value = await execShellCommand("npm bin -g");


var dir = null;
if (!value || value.length === 0) {

// We couldn't infer path from `npm bin`. Let's try to get it from
// Environment variables set by NPM when it runs.
// npm_config_prefix points to NPM's installation directory where `bin` folder is available
// Ex: /Users/foo/.nvm/versions/node/v4.3.0
var env = process.env;
if (env && env.npm_config_prefix) {
dir = path.join(env.npm_config_prefix, "bin");
}
} else {
dir = value.trim();
}

await mkdirp(dir);
return dir;
}

async function verifyAndPlaceBinary(binName, binPath, callback) {
if (!fs.existsSync(path.join(binPath, binName))) return callback('Downloaded binary does not contain the binary specified in configuration - ' + binName);

// Get installation path for executables under node
const installationPath= await getInstallationPath();
// Copy the executable to the path
fs.rename(path.join(binPath, binName), path.join(installationPath, binName),(err)=>{
if(!err){
console.info("Installed cli successfully");
callback(null);
}else{
callback(err);
}
});
}

function validateConfiguration(packageJson) {

if (!packageJson.version) {
return "'version' property must be specified";
}

if (!packageJson.goBinary || _typeof(packageJson.goBinary) !== "object") {
return "'goBinary' property must be defined and be an object";
}

if (!packageJson.goBinary.name) {
return "'name' property is necessary";
}

if (!packageJson.goBinary.path) {
return "'path' property is necessary";
}
}

function parsePackageJson() {
if (process.arch !=="arm64" && process.platform !== "darwin"){
if (!(process.arch in ARCH_MAPPING)) {
console.error("Installation is not supported for this architecture: " + process.arch);
return;
}
}

if (!(process.platform in PLATFORM_MAPPING)) {
console.error("Installation is not supported for this platform: " + process.platform);
return;
}

var packageJsonPath = path.join(".", "package.json");
if (!fs.existsSync(packageJsonPath)) {
console.error("Unable to find package.json. " + "Please run this script at root of the package you want to be installed");
return;
}

var packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
var error = validateConfiguration(packageJson);
if (error && error.length > 0) {
console.error("Invalid package.json: " + error);
return;
}

// We have validated the config. It exists in all its glory
var binName = packageJson.goBinary.name;
var binPath = packageJson.goBinary.path;
var version = packageJson.version;
if (version[0] === 'v') version = version.substr(1); // strip the 'v' if necessary v0.0.1 => 0.0.1

// Binary name on Windows has .exe suffix
if (process.platform === "win32") {
binName += ".exe";
}


return {
binName: binName,
binPath: binPath,
version: version
};
}

/**
* Reads the configuration from application's package.json,
* validates properties, copied the binary from the package and stores at
* ./bin in the package's root. NPM already has support to install binary files
* specific locations when invoked with "npm install -g"
*
* See: https://docs.npmjs.com/files/package.json#bin
*/
var INVALID_INPUT = "Invalid inputs";
async function install(callback) {

var opts = parsePackageJson();
if (!opts) return callback(INVALID_INPUT);
mkdirp.sync(opts.binPath);
console.info(`Copying the relevant binary for your platform ${process.platform}`);
let src= `./dist/go-ios-${PLATFORM_MAPPING[process.platform]}-${ARCH_MAPPING[process.arch]}_${PLATFORM_MAPPING[process.platform]}_${ARCH_MAPPING[process.arch]}/${opts.binName}`;
if (process.arch ==="arm64" && process.platform === "darwin"){
console.log("using amd64 build on M1 mac")
src= `./dist/go-ios-${process.platform}-amd64_${process.platform}_amd64/${opts.binName}`;
}
await execShellCommand(`cp ${src} ${opts.binPath}/${opts.binName}`);
await verifyAndPlaceBinary(opts.binName, opts.binPath, callback);
console.log("\x1b[32m","go-ios installed, run 'ios --help' for details\n\n")
}

async function uninstall(callback) {
var opts = parsePackageJson();
try {
const installationPath = await getInstallationPath();
fs.unlink(path.join(installationPath, opts.binName),(err)=>{
if(err){
return callback(err);
}
});
} catch (ex) {
// Ignore errors when deleting the file.
}
console.info("Uninstalled cli successfully");
return callback(null);
}

// Parse command line arguments and call the right method
var actions = {
"install": install,
"uninstall": uninstall
};
/**
* Executes a shell command and return it as a Promise.
* @param cmd {string}
* @return {Promise<string>}
*/
function execShellCommand(cmd) {
const exec = require('child_process').exec;
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.warn(error);
}
resolve(stdout? stdout : stderr);
});
});
}

var argv = process.argv;
if (argv && argv.length > 2) {
var cmd = process.argv[2];
if (!actions[cmd]) {
console.log("Invalid command. `install` and `uninstall` are the only supported commands");
process.exit(1);
}

actions[cmd](function (err) {
if (err) {
console.error(err);
process.exit(1);
} else {
process.exit(0);
}
});
}

0 comments on commit db84353

Please sign in to comment.