Comparing version 1.9.99 to 2.0.0
322
forceios.js
#!/usr/bin/env node | ||
console.log('Coming soon!'); | ||
var exec = require('child_process').exec, | ||
path = require('path'), | ||
commandLineUtils = require('./HybridShared/node/commandLineUtils'); | ||
var outputColors = { | ||
'red': '\x1b[31;1m', | ||
'green': '\x1b[32;1m', | ||
'yellow': '\x1b[33;1m', | ||
'magenta': '\x1b[35;1m', | ||
'cyan': '\x1b[36;1m', | ||
'reset': '\x1b[0m' | ||
} | ||
var dependencyType = { | ||
'FILE': 0, | ||
'DIR': 1, | ||
'ARCHIVE': 2 | ||
} | ||
var commandLineArgs = process.argv.slice(2, process.argv.length); | ||
var command = commandLineArgs.shift(); | ||
if (typeof command !== 'string') { | ||
usage(); | ||
process.exit(1); | ||
} | ||
var argProcessorList = createArgProcessorList(); | ||
var commandLineArgsMap; | ||
commandLineUtils.processArgsInteractive(commandLineArgs, argProcessorList, function (outputArgsMap) { | ||
commandLineArgsMap = outputArgsMap; | ||
switch (command) { | ||
case 'create': | ||
createApp(); | ||
break; | ||
default: | ||
console.log(outputColors.red + 'Unknown option: \'' + command + '\'.' + outputColors.reset); | ||
usage(); | ||
process.exit(2); | ||
} | ||
}); | ||
function usage() { | ||
console.log(outputColors.cyan + 'Usage:'); | ||
console.log(outputColors.magenta + 'forceios create'); | ||
console.log(' --apptype=<Application Type> (native, hybrid_remote, hybrid_local)'); | ||
console.log(' --appname=<Application Name>'); | ||
console.log(' --companyid=<Company Identifier> (com.myCompany.myApp)'); | ||
console.log(' --organization=<Organization Name> (Your company\'s/organization\'s name)'); | ||
console.log(' --startpage=<App Start Page> (The start page of your remote app. Only required for hybrid_remote)'); | ||
console.log(' [--outputdir=<Output directory> (Defaults to the current working directory)]'); | ||
console.log(' [--appid=<Salesforce App Identifier> (The Consumer Key for your app. Defaults to the sample app.)]'); | ||
console.log(' [--callbackuri=<Salesforce App Callback URL (The Callback URL for your app. Defaults to the sample app.)]' + outputColors.reset); | ||
} | ||
function createApp() { | ||
var appType = commandLineArgsMap.apptype; | ||
if (appType !== 'native' && appType !== 'hybrid_remote' && appType !== 'hybrid_local') { | ||
console.log(outputColors.red + 'Unrecognized app type: \'' + appType + '\'.' + outputColors.reset + 'App type must be native, hybrid_remote, or hybrid_local.'); | ||
usage(); | ||
process.exit(4); | ||
} | ||
var createAppExecutable = (appType === 'native' ? | ||
path.join(__dirname, 'Templates', 'NativeAppTemplate', 'createApp.sh') : | ||
path.join(__dirname, 'Templates', 'HybridAppTemplate', 'createApp.sh') | ||
); | ||
// Calling out to the shell, so re-quote the command line arguments. | ||
var newCommandLineArgs = buildArgsFromArgMap(); | ||
var createAppProcess = exec(createAppExecutable + ' ' + newCommandLineArgs, function(error, stdout, stderr) { | ||
if (stdout) console.log(stdout); | ||
if (stderr) console.log(stderr); | ||
if (error) { | ||
console.log(outputColors.red + 'There was an error creating the app.' + outputColors.reset); | ||
process.exit(5); | ||
} | ||
// Copy dependencies | ||
copyDependencies(appType, function(success, msg) { | ||
if (success) { | ||
if (msg) console.log(outputColors.green + msg + outputColors.reset); | ||
console.log(outputColors.green + 'Congratulations! You have successfully created your app.' + outputColors.reset); | ||
} else { | ||
if (msg) console.log(outputColors.red + msg + outputColors.reset); | ||
console.log(outputColors.red + 'There was an error creating the app.' + outputColors.reset); | ||
} | ||
}); | ||
}); | ||
} | ||
function buildArgsFromArgMap() { | ||
var argLine = ''; | ||
argLine += ' -t "' + commandLineArgsMap.apptype + '"'; | ||
argLine += ' -n "' + commandLineArgsMap.appname + '"'; | ||
argLine += ' -c "' + commandLineArgsMap.companyid + '"'; | ||
argLine += ' -g "' + commandLineArgsMap.organization + '"'; | ||
if (commandLineArgsMap.outputdir) | ||
argLine += ' -o "' + commandLineArgsMap.outputdir + '"'; | ||
if (commandLineArgsMap.appid) | ||
argLine += ' -a "' + commandLineArgsMap.appid + '"'; | ||
if (commandLineArgsMap.callbackuri) | ||
argLine += ' -u "' + commandLineArgsMap.callbackuri + '"'; | ||
if (commandLineArgsMap.startpage) | ||
argLine += ' -s "' + commandLineArgsMap.startpage + '"'; | ||
return argLine; | ||
} | ||
function copyDependencies(appType, callback) { | ||
var outputDirMap = createOutputDirectoriesMap(); | ||
var dependencyPackages = createDependencyPackageMap(outputDirMap); | ||
var dependencies = [ | ||
dependencyPackages.sdkresources, | ||
dependencyPackages.commonutils, | ||
dependencyPackages.oauth, | ||
dependencyPackages.sdkcore, | ||
dependencyPackages.openssl, | ||
dependencyPackages.sqlcipher | ||
]; | ||
switch (appType) { | ||
case 'native': | ||
dependencies.push(dependencyPackages.restkit); | ||
dependencies.push(dependencyPackages.nativesdk); | ||
break; | ||
case 'hybrid_local': | ||
dependencies.push(dependencyPackages.cordovaJs); | ||
dependencies.push(dependencyPackages.hybridForcePlugins); | ||
dependencies.push(dependencyPackages.hybridForceTk); | ||
dependencies.push(dependencyPackages.hybridSmartSync); | ||
dependencies.push(dependencyPackages.hybridSampleAppHtml); | ||
dependencies.push(dependencyPackages.hybridSampleAppJs); | ||
dependencies.push(dependencyPackages.jquery); | ||
dependencies.push(dependencyPackages.backbone); | ||
case 'hybrid_remote': | ||
dependencies.push(dependencyPackages.cordovaBin); | ||
dependencies.push(dependencyPackages.cordovaConfig); | ||
dependencies.push(dependencyPackages.cordovaCaptureBundle); | ||
dependencies.push(dependencyPackages.hybridsdk); | ||
break; | ||
} | ||
console.log(outputColors.cyan + 'Staging app dependencies...' + outputColors.reset); | ||
copyDependenciesHelper(dependencies, callback); | ||
} | ||
function copyDependenciesHelper(dependencies, callback) { | ||
if (dependencies.length === 0) { | ||
return callback(true, null); | ||
} | ||
var dependencyObj = dependencies.shift(); | ||
switch (dependencyObj.dependencyType) { | ||
case dependencyType.ARCHIVE: | ||
// Zip archive. Uncompress to the app's dependencies directory. | ||
console.log(outputColors.yellow + 'Uncompressing ' + path.basename(dependencyObj.srcPath) + ' to ' + dependencyObj.destPath + outputColors.reset); | ||
exec('unzip "' + dependencyObj.srcPath + '" -d "' + dependencyObj.destPath + '"', function(error, stdout, stderr) { | ||
if (error) { | ||
return callback(false, 'There was an error uncompressing the archive \'' + dependencyObj.srcPath + '\' to \'' + dependencyObj.destPath + '\': ' + error); | ||
} | ||
copyDependenciesHelper(dependencies, callback); | ||
}); | ||
break; | ||
case dependencyType.DIR: | ||
// Simple folder. Recursive copy to the app's dependencies directory. | ||
console.log(outputColors.yellow + 'Copying ' + path.basename(dependencyObj.srcPath) + ' to ' + dependencyObj.destPath + outputColors.reset); | ||
exec('cp -R "' + dependencyObj.srcPath + '" "' + dependencyObj.destPath + '"', function(error, stdout, stderr) { | ||
if (error) { | ||
return callback(false, 'Error copying directory \'' + dependencyObj.srcPath + '\' to \'' + dependencyObj.destPath + '\': ' + error); | ||
} | ||
copyDependenciesHelper(dependencies, callback); | ||
}); | ||
break; | ||
case dependencyType.FILE: | ||
// Simple file(s). Copy to the app's dependencies directory. | ||
console.log(outputColors.yellow + 'Copying ' + path.basename(dependencyObj.srcPath) + ' to ' + dependencyObj.destPath + outputColors.reset); | ||
exec('cp "' + dependencyObj.srcPath + '" "' + dependencyObj.destPath + '"', function(error, stdout, stderr) { | ||
if (error) { | ||
return callback(false, 'Error copying file(s) \'' + dependencyObj.srcPath + '\' to \'' + dependencyObj.destPath + '\': ' + error); | ||
} | ||
copyDependenciesHelper(dependencies, callback); | ||
}); | ||
break; | ||
} | ||
} | ||
function createOutputDirectoriesMap() { | ||
var outputDirMap = {}; | ||
// NB: Arguments should have already been verified at this point. | ||
var appName = commandLineArgsMap.appname; | ||
var outputDir = commandLineArgsMap.outputdir; | ||
if (!outputDir) outputDir = process.cwd(); | ||
outputDir = path.resolve(outputDir); | ||
outputDirMap.appBaseContentDir = path.join(outputDir, appName, appName); | ||
outputDirMap.appDependenciesDir = path.join(outputDirMap.appBaseContentDir, 'Dependencies'); | ||
outputDirMap.hybridAppWwwDir = path.join(outputDirMap.appBaseContentDir, 'www'); | ||
return outputDirMap; | ||
} | ||
function createDependencyPackageMap(outputDirMap) { | ||
var packageMap = {}; | ||
packageMap.sdkresources = makePackageObj(path.join(__dirname, 'Dependencies', 'SalesforceSDKResources.bundle'), outputDirMap.appBaseContentDir, dependencyType.DIR); | ||
packageMap.cordovaBin = makePackageObj(path.join(__dirname, 'Dependencies', 'Cordova', 'Cordova-Release.zip'), outputDirMap.appDependenciesDir, dependencyType.ARCHIVE); | ||
packageMap.cordovaConfig = makePackageObj(path.join(__dirname, 'Dependencies', 'Cordova', 'config.xml'), outputDirMap.appBaseContentDir, dependencyType.FILE); | ||
packageMap.cordovaJs = makePackageObj(path.join(__dirname, 'Dependencies', 'Cordova', 'cordova-2.3.0.js'), outputDirMap.hybridAppWwwDir, dependencyType.FILE); | ||
packageMap.cordovaCaptureBundle = makePackageObj(path.join(__dirname, 'Dependencies', 'Cordova', 'Capture.bundle'), outputDirMap.appBaseContentDir, dependencyType.DIR); | ||
packageMap.hybridForcePlugins = makePackageObj(path.join(__dirname, 'HybridShared', 'libs', 'cordova.force.js'), outputDirMap.hybridAppWwwDir, dependencyType.FILE); | ||
packageMap.hybridForceTk = makePackageObj(path.join(__dirname, 'HybridShared', 'libs', 'forcetk.mobilesdk.js'), outputDirMap.hybridAppWwwDir, dependencyType.FILE); | ||
packageMap.hybridSmartSync = makePackageObj(path.join(__dirname, 'HybridShared', 'libs', 'smartsync.js'), outputDirMap.hybridAppWwwDir, dependencyType.FILE); | ||
packageMap.jquery = makePackageObj(path.join(__dirname, 'HybridShared', 'external', 'jquery'), outputDirMap.hybridAppWwwDir, dependencyType.DIR); | ||
packageMap.backbone = makePackageObj(path.join(__dirname, 'HybridShared', 'external', 'backbone'), outputDirMap.hybridAppWwwDir, dependencyType.DIR); | ||
packageMap.hybridSampleAppHtml = makePackageObj(path.join(__dirname, 'HybridShared', 'SampleApps', 'contactexplorer', 'index.html'), outputDirMap.hybridAppWwwDir, dependencyType.FILE); | ||
packageMap.hybridSampleAppJs = makePackageObj(path.join(__dirname, 'HybridShared', 'SampleApps', 'contactexplorer', 'inline.js'), outputDirMap.hybridAppWwwDir, dependencyType.FILE); | ||
packageMap.hybridsdk = makePackageObj(path.join(__dirname, 'Dependencies', 'SalesforceHybridSDK-Release.zip'), outputDirMap.appDependenciesDir, dependencyType.ARCHIVE); | ||
packageMap.nativesdk = makePackageObj(path.join(__dirname, 'Dependencies', 'SalesforceNativeSDK-Release.zip'), outputDirMap.appDependenciesDir, dependencyType.ARCHIVE); | ||
packageMap.oauth = makePackageObj(path.join(__dirname, 'Dependencies', 'SalesforceOAuth-Release.zip'), outputDirMap.appDependenciesDir, dependencyType.ARCHIVE); | ||
packageMap.sdkcore = makePackageObj(path.join(__dirname, 'Dependencies', 'SalesforceSDKCore-Release.zip'), outputDirMap.appDependenciesDir, dependencyType.ARCHIVE); | ||
packageMap.restkit = makePackageObj(path.join(__dirname, 'Dependencies', 'ThirdParty', 'RestKit'), outputDirMap.appDependenciesDir, dependencyType.DIR); | ||
packageMap.commonutils = makePackageObj(path.join(__dirname, 'Dependencies', 'ThirdParty', 'SalesforceCommonUtils'), outputDirMap.appDependenciesDir, dependencyType.DIR); | ||
packageMap.openssl = makePackageObj(path.join(__dirname, 'Dependencies', 'ThirdParty', 'openssl'), outputDirMap.appDependenciesDir, dependencyType.DIR); | ||
packageMap.sqlcipher = makePackageObj(path.join(__dirname, 'Dependencies', 'ThirdParty', 'sqlcipher'), outputDirMap.appDependenciesDir, dependencyType.DIR); | ||
return packageMap; | ||
} | ||
function makePackageObj(srcPath, destPath, dependencyType) { | ||
return { 'srcPath': srcPath, 'destPath': destPath, 'dependencyType': dependencyType }; | ||
} | ||
// ----- | ||
// Input argument validation / processing. | ||
// ----- | ||
function createArgProcessorList() { | ||
var argProcessorList = new commandLineUtils.ArgProcessorList(); | ||
// App type | ||
argProcessorList.addArgProcessor('apptype', 'Enter your application type (native, hybrid_remote, or hybrid_local):', function(appType) { | ||
appType = appType.trim(); | ||
if (appType !== 'native' && appType !== 'hybrid_remote' && appType !== 'hybrid_local') | ||
return new commandLineUtils.ArgProcessorOutput(false, 'App type must be native, hybrid_remote, or hybrid_local.'); | ||
return new commandLineUtils.ArgProcessorOutput(true, appType); | ||
}); | ||
// App name | ||
argProcessorList.addArgProcessor('appname', 'Enter your application name:', function(appName) { | ||
if (appName.trim() === '') | ||
return new commandLineUtils.ArgProcessorOutput(false, 'Invalid value for app name: \'' + appName + '\''); | ||
return new commandLineUtils.ArgProcessorOutput(true, appName.trim()); | ||
}); | ||
// Company Identifier | ||
argProcessorList.addArgProcessor('companyid', 'Enter your company identifier (com.mycompany):', function(companyId) { | ||
if (companyId.trim() === '') | ||
return new commandLineUtils.ArgProcessorOutput(false, 'Invalid value for company identifier: \'' + companyId + '\''); | ||
// TODO: Update the company ID format as necessary. | ||
return new commandLineUtils.ArgProcessorOutput(true, companyId.trim()); | ||
}); | ||
// Organization | ||
argProcessorList.addArgProcessor('organization', 'Enter your organization name (Acme, Inc.):', function(org) { | ||
if (org.trim() === '') | ||
return new commandLineUtils.ArgProcessorOutput(false, 'Invalid value for organization: \'' + org + '\''); | ||
return new commandLineUtils.ArgProcessorOutput(true, org.trim()); | ||
}); | ||
// Start page | ||
argProcessorList.addArgProcessor( | ||
'startpage', | ||
'Enter the start page for your app (only applicable for hybrid_remote apps):', | ||
function(startPage, argsMap) { | ||
if (argsMap && argsMap.apptype === 'hybrid_remote') { | ||
if (startPage.trim() === '') | ||
return new commandLineUtils.ArgProcessorOutput(false, 'Invalid value for start page: \'' + startPage + '\''); | ||
return new commandLineUtils.ArgProcessorOutput(true, startPage.trim()); | ||
} | ||
// Unset any value here, as it doesn't apply for non-remote apps. | ||
return new commandLineUtils.ArgProcessorOutput(true, undefined); | ||
}, | ||
function (argsMap) { | ||
return (argsMap['apptype'] === 'hybrid_remote'); | ||
} | ||
); | ||
// Output dir | ||
argProcessorList.addArgProcessor('outputdir', 'Enter the output directory for your app (defaults to the current directory):', function(outputDir) { | ||
if (outputDir.trim() === '') | ||
// Just unset the value. The underlying script will take care of the default. | ||
return new commandLineUtils.ArgProcessorOutput(true, undefined); | ||
return new commandLineUtils.ArgProcessorOutput(true, outputDir.trim()); | ||
}); | ||
// Connected App ID | ||
argProcessorList.addArgProcessor('appid', 'Enter your Connected App ID (defaults to the sample app\'s ID):', function(appId) { | ||
if (appId.trim() === '') | ||
// Just unset the value. The underlying script will take care of the default. | ||
return new commandLineUtils.ArgProcessorOutput(true, undefined); | ||
return new commandLineUtils.ArgProcessorOutput(true, appId.trim()); | ||
}); | ||
// Connected App Callback URI | ||
argProcessorList.addArgProcessor('callbackuri', 'Enter your Connected App Callback URI (defaults to the sample app\'s URI):', function(callbackUri) { | ||
if (callbackUri.trim() === '') | ||
// Just unset the value. The underlying script will take care of the default. | ||
return new commandLineUtils.ArgProcessorOutput(true, undefined); | ||
return new commandLineUtils.ArgProcessorOutput(true, callbackUri.trim()); | ||
}); | ||
return argProcessorList; | ||
} |
{ | ||
"name": "forceios", | ||
"version": "1.9.99", | ||
"version": "2.0.0", | ||
"description": "Utilities for creating mobile apps based on the Salesforce Mobile SDK for iOS", | ||
@@ -5,0 +5,0 @@ "keywords": [ "mobilesdk", "ios", "salesforce", "mobile", "sdk" ], |
@@ -1,11 +0,71 @@ | ||
# Salesforce Mobile SDK Packages | ||
# Salesforce Mobile SDK for iOS Package | ||
### Coming soon! | ||
The **forceios** npm package allows users to create iOS mobile applications to interface with the [Salesforce Platform](http://www.salesforce.com/platform/overview/), leveraging the [Salesforce Mobile SDK for iOS](https://github.com/forcedotcom/SalesforceMobileSDK-iOS). | ||
This repository contains various installation packages associated with the Salesforce Mobile SDK. | ||
## Getting Started | ||
- The Salesforce Mobile SDK for Android source repository lives [here](https://github.com/forcedotcom/SalesforceMobileSDK-Android). | ||
If you're new to mobile development, or the force.com platform, you may want to start at the [Mobile SDK landing page](http://wiki.developerforce.com/page/Mobile_SDK). This page offers a variety of resources to help you determine the best technology path for creating your app, as well as many guides and blog posts detailing how to work with the Mobile SDK. | ||
- The Salesforce Mobile SDK for iOS source repository lives [here](https://github.com/forcedotcom/SalesforceMobileSDK-iOS). | ||
But assuming you're all read up, here's how to get started with the **forceios** package to create the starting point for your mobile application. | ||
## Install the forceios Package | ||
Because forceios is a command-line utility, we recommend installing it globally, so that it's easily accessible on your path: | ||
sudo npm install forceios -g | ||
You're of course welcome to install it locally as well: | ||
npm install forceios | ||
In this case, you can access the forceios app at `[Install Directory]/node_modules/.bin/forceios`. | ||
## Using forceios | ||
For the rest of this document, we'll assume that `forceios` is on your path. | ||
Typing `forceios` with no arguments gives you a breakdown of the usage: | ||
$ forceios | ||
Usage: | ||
forceios create | ||
--apptype=<Application Type> (native, hybrid_remote, hybrid_local) | ||
--appname=<Application Name> | ||
--companyid=<Company Identifier> (com.myCompany.myApp) | ||
--organization=<Organization Name> (Your company's/organization's name) | ||
--startpage=<App Start Page> (The start page of your remote app. Only required for hybrid_remote) | ||
[--outputdir=<Output directory> (Defaults to the current working directory)] | ||
[--appid=<Salesforce App Identifier> (The Consumer Key for your app. Defaults to the sample app.)] | ||
[--callbackuri=<Salesforce App Callback URL (The Callback URL for your app. Defaults to the sample app.)] | ||
**Note:** You can specify any or all of the arguments as command line options as specified in the usage. If you run `forceios create` with missing arguments, it prompts you for each missing option interactively. | ||
Once the creation script completes, you'll have a fully functioning basic application of the type you specified. The new application is an Xcode project that you can peruse, run, and debug. | ||
### forceios create options | ||
**App Type:** The type of application you wish to develop: | ||
- **native** — A fully native iOS application | ||
- **hybrid\_remote** — A hybrid application, based on the [Cordova](http://cordova.apache.org/) framework, that runs in a native container. The app contents live in the cloud as a [Visualforce](http://wiki.developerforce.com/page/An_Introduction_to_Visualforce) application | ||
- **hybrid\_local** — A hybrid application, based on the Cordova framework, that runs in a native container. The app contents are developed locally in the Xcode project, and are deployed to the device itself when the app is built | ||
**App Name:** The name of your application | ||
**Company ID:** An identifier for your company, similar to a Java package (e.g. `com.acme.MobileApps`). This concatenates with the app name to form the unique identifier for your app in the App Store. | ||
**Organization:** The name of your company or organization. For example, `Acme Widgets, Inc.` | ||
**Start Page:** \( *Required for hybrid\_remote apps only* \) The starting page of your application on salesforce.com. This is the entry point of your remote application, though it's only the path, not the server portion of the URL. For instance, `/apex/MyVisualforceStartPage`. | ||
**Output Directory:** \( *optional* \) The directory where you want your app to be created. If not specified, it will be created in your current working directory. | ||
**App ID:** \( *optional* \) The Connected App Consumer Key that identifies your app in the cloud. This argument defaults to a sample key to allow you to test your app. However, **you _must_ specify your own Consumer Key before you submit your app to the App Store**. | ||
**Callback URI:** \( *optional* \) The Callback URL associated with your Connected App. As with the App ID, this argument defaults to a value for a sample app. **You _must_ specify your own Callback URL before you submit your app to the App Store**. | ||
## More information | ||
- The Salesforce Mobile SDK for Android (and package) source repository lives [here](https://github.com/forcedotcom/SalesforceMobileSDK-Android). | ||
- See [our developerforce site](http://wiki.developerforce.com/page/Mobile_SDK) for more information about how you can leverage the Salesforce Mobile SDK with the force.com platform. |
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Trivial Package
Supply chain riskPackages less than 10 lines of code are easily copied into your own project and may not warrant the additional supply chain risk of an external dependency.
Found 1 instance in 1 package
42136969
373
17163
72
1
1
4
7