Compare commits

...

27 Commits

Author SHA1 Message Date
Steven
9d7dd3a713 Publish
- @now/python@0.1.1-canary.0
2019-05-02 11:32:59 -04:00
Steven
4f867b320d [now-python] Upgrade build env to python3.6 (#450)
* [now-python] Upgarde build env to python3.6

* Add support for isDev
2019-05-02 11:00:39 -04:00
Nathan Rajlich
c153690104 Publish
- @now/build-utils@0.5.2-canary.0
 - @now/go@0.4.3-canary.0
 - @now/next@0.2.1-canary.0
 - @now/static-build@0.5.3-canary.0
2019-05-01 23:34:18 -07:00
Nathan Rajlich
8c1b96edf7 [now-build-utils] Use cross-spawn for Windows support (#449) 2019-05-01 23:26:20 -07:00
Carlos Alexandro Becker
15c83a69f7 [now-go] Add support for config.includeFiles (#447) 2019-05-01 17:39:53 -04:00
Steven
0986de85ee [now-static-build] Warn when now-dev script is missing (#443)
* Warn when now-dev script is missing

* Add link to local dev docs

* Update packages/now-static-build/index.js

Co-Authored-By: styfle <steven@ceriously.com>

* Fix url
2019-05-01 17:32:50 -04:00
Leo Lamprecht
94c5d83ccc Copy the entire process environment to child (#448)
* Copy the entire process environment to child

* Removed lockfile

* Removed useless code

* Add comment
2019-05-01 22:26:35 +02:00
Steven
ff49b9d32d Publish
- @now/node-server@0.6.1-canary.0
 - @now/node@0.6.1-canary.0
2019-05-01 14:20:43 -04:00
Steven
ec5290dab1 [node-node] Bump ncc to 0.18.2 (#446) 2019-05-01 12:19:43 -04:00
Steven
4f758ec84e Create CODE_OF_CONDUCT.md (#444) 2019-05-01 09:04:34 -04:00
Steven
7951be156a Publish
- @now/build-utils@0.5.1
 - @now/go@0.4.2
 - @now/static-build@0.5.2
2019-04-30 10:33:52 -04:00
Nathan Rajlich
1bafc1d7b7 Publish
- @now/go@0.4.1
2019-04-29 18:03:38 -07:00
Sophearak Tha
1493101325 [now-go] Improve speed for now dev (#438)
* Improve speed for build() `@now/go` `now dev`

* Remove duplicate line

* Improve code flow

* Improve logging information

* no need to download Go if it available
2019-04-29 18:01:09 -07:00
Nathan Rajlich
824b044a96 Publish
- @now/static-build@0.5.1
2019-04-29 14:57:30 -07:00
Nathan Rajlich
0978be4c3d Publish
- @now/static-build@0.5.1-canary.0
2019-04-29 14:00:45 -07:00
Nathan Rajlich
dc832aa6c3 Regenerate yarn.lock file 2019-04-29 14:00:26 -07:00
Nathan Rajlich
8df77fe4fa [now-build-utils] Wait for the dev server to print the URL with correct port number (#439)
This is an alternative approach to detecting when the dev server is
ready to receive HTTP traffic, also bumps the timeout to 5 minutes.
2019-04-29 13:58:44 -07:00
Sophearak Tha
ff413b45fa Publish
- @now/go@0.4.1-canary.3
2019-04-29 16:46:58 +07:00
Sophearak Tha
e7befb5dc1 Make install @now/go faster (#435) 2019-04-29 16:46:08 +07:00
Steven
b898f82771 [now-go] Use optimized build flags (#428)
* Add optimized build output

* Add `config.ldsflags`
2019-04-29 09:41:50 +07:00
Leo Lamprecht
e6b22cb0df Publish
- @now/go@0.4.1-canary.2
2019-04-28 19:54:24 +00:00
Sophearak Tha
cbfe4a133d Using full path for checking against entrypoint (#433) 2019-04-29 00:44:31 +07:00
Sophearak Tha
823b78c626 Publish
- @now/go@0.4.1-canary.1
2019-04-28 21:22:30 +07:00
Sophearak Tha
03e1255043 Improve rebuild speed for now dev (#432) 2019-04-28 20:56:07 +07:00
Steven
3373cbca4e Publish
- @now/build-utils@0.5.1-canary.0
 - @now/go@0.4.1-canary.0
2019-04-25 17:11:31 -04:00
Sophearak Tha
4fba4b5f67 [now-go] Migrated to TypeScript and support Builder v2 API (#412)
* Migrated `@now/go` to TypeScript

* Add support for Builder v2 API

* Add now-go to .eslintignore

* Update go bin path

* Update packages/now-go/.gitignore

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Update packages/now-go/go-helpers.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Update packages/now-go/go-helpers.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Using American English for consistency

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Rename analyse.go to analyze.go

* Update packages/now-go/go-helpers.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Remove `mkdirp-promise` from now-go

* Ensure `watch` directory-aware given `entrypoint` in subdirectory

* Support export struct type declaration

* Improve log

* Add type to `analyzed`

* Update packages/now-go/index.ts

Co-Authored-By: sophearak <t.sophearak@gmail.com>

* Migrate test fixtures from `add/now-go-tests`
2019-04-25 17:07:56 -04:00
Steven
9fcf6da3c1 Add comment to fsPath about absolute path (#427) 2019-04-25 11:27:36 -04:00
40 changed files with 896 additions and 371 deletions

View File

@@ -8,3 +8,4 @@
/packages/now-node-bridge/*
/packages/now-python/*
/packages/now-optipng/dist/*
/packages/now-go/*

74
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,74 @@
## Code of Conduct
### Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
### Our Standards
Examples of behavior that contributes to creating a positive environment
include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or
advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
### Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
### Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
### Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at [abuse@zeit.co](mailto:abuse@zeit.co). All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
### Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "0.5.0",
"version": "0.5.2-canary.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -10,8 +10,10 @@
"directory": "packages/now-build-utils"
},
"dependencies": {
"@types/cross-spawn": "6.0.0",
"async-retry": "1.2.3",
"async-sema": "2.1.4",
"cross-spawn": "6.0.5",
"end-of-stream": "1.4.1",
"fs-extra": "7.0.0",
"glob": "7.1.3",

View File

@@ -1,22 +1,28 @@
import assert from 'assert';
import fs from 'fs-extra';
import path from 'path';
import { spawn, SpawnOptions } from 'child_process';
import spawn from 'cross-spawn';
import { SpawnOptions } from 'child_process';
function spawnAsync(command: string, args: string[], cwd: string, opts: SpawnOptions = {}) {
function spawnAsync(
command: string,
args: string[],
cwd: string,
opts: SpawnOptions = {}
) {
return new Promise<void>((resolve, reject) => {
const stderrLogs: Buffer[] = []
const stderrLogs: Buffer[] = [];
opts = { stdio: 'inherit', cwd, ...opts };
const child = spawn(command, args, opts);
if (opts.stdio === 'pipe'){
if (opts.stdio === 'pipe') {
child.stderr.on('data', data => stderrLogs.push(data));
}
child.on('error', reject);
child.on('close', (code, signal) => {
if (code === 0) {
return resolve()
return resolve();
}
const errorLogs = stderrLogs.map(line => line.toString()).join('');
@@ -58,13 +64,15 @@ async function scanParentDirs(destPath: string, scriptName?: string) {
// eslint-disable-next-line no-await-in-loop
if (await fs.pathExists(packageJsonPath)) {
// eslint-disable-next-line no-await-in-loop
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
const packageJson = JSON.parse(
await fs.readFile(packageJsonPath, 'utf8')
);
hasScript = Boolean(
packageJson.scripts && scriptName && packageJson.scripts[scriptName],
packageJson.scripts && scriptName && packageJson.scripts[scriptName]
);
// eslint-disable-next-line no-await-in-loop
hasPackageLockJson = await fs.pathExists(
path.join(currentDestPath, 'package-lock.json'),
path.join(currentDestPath, 'package-lock.json')
);
break;
}
@@ -77,7 +85,10 @@ async function scanParentDirs(destPath: string, scriptName?: string) {
return { hasScript, hasPackageLockJson };
}
export async function installDependencies(destPath: string, args: string[] = []) {
export async function installDependencies(
destPath: string,
args: string[] = []
) {
assert(path.isAbsolute(destPath));
let commandArgs = args;
@@ -91,7 +102,7 @@ export async function installDependencies(destPath: string, args: string[] = [])
// Node.js version that `@now/node` and `@now/node-server` use
npm_config_target: '8.10.0',
},
stdio: 'pipe'
stdio: 'pipe',
};
if (hasPackageLockJson) {
@@ -107,7 +118,7 @@ export async function installDependencies(destPath: string, args: string[] = [])
'yarn',
['--cwd', destPath].concat(commandArgs),
destPath,
opts as SpawnOptions,
opts as SpawnOptions
);
}
}
@@ -120,7 +131,7 @@ export async function runPackageJsonScript(
assert(path.isAbsolute(destPath));
const { hasScript, hasPackageLockJson } = await scanParentDirs(
destPath,
scriptName,
scriptName
);
if (!hasScript) return false;
@@ -129,7 +140,12 @@ export async function runPackageJsonScript(
await spawnAsync('npm', ['run', scriptName], destPath, opts);
} else {
console.log(`running "yarn run ${scriptName}"`);
await spawnAsync('yarn', ['--cwd', destPath, 'run', scriptName], destPath, opts);
await spawnAsync(
'yarn',
['--cwd', destPath, 'run', scriptName],
destPath,
opts
);
}
return true;

View File

@@ -5,6 +5,9 @@ export interface File {
type: string;
mode: number;
toStream: () => NodeJS.ReadableStream;
/**
* The absolute path to the file in the filesystem
*/
fsPath?: string;
}

View File

@@ -1,5 +1,6 @@
node_modules
*.log
/?.js
/go
/get-exported-function-name
/analyze
*.js
!util/install.js

View File

@@ -0,0 +1,5 @@
*.ts
test
tsconfig.json
package-lock.json
yarn.lock

View File

@@ -1,129 +0,0 @@
const tar = require('tar');
const execa = require('execa');
const fetch = require('node-fetch');
const { mkdirp } = require('fs-extra');
const { dirname, join } = require('path');
const debug = require('debug')('@now/go:go-helpers');
const archMap = new Map([['x64', 'amd64'], ['x86', '386']]);
const platformMap = new Map([['win32', 'windows']]);
// Location where the `go` binary will be installed after `postinstall`
const GO_DIR = join(__dirname, 'go');
const GO_BIN = join(GO_DIR, 'bin/go');
const getPlatform = p => platformMap.get(p) || p;
const getArch = a => archMap.get(a) || a;
const getGoUrl = (version, platform, arch) => {
const goArch = getArch(arch);
const goPlatform = getPlatform(platform);
const ext = platform === 'win32' ? 'zip' : 'tar.gz';
return `https://dl.google.com/go/go${version}.${goPlatform}-${goArch}.${ext}`;
};
async function getExportedFunctionName(filePath) {
debug('Detecting handler name for %o', filePath);
const bin = join(__dirname, 'get-exported-function-name');
const args = [filePath];
const name = await execa.stdout(bin, args);
debug('Detected exported name %o', name);
return name;
}
// Creates a `$GOPATH` directory tree, as per `go help gopath` instructions.
// Without this, `go` won't recognize the `$GOPATH`.
function createGoPathTree(goPath, platform, arch) {
const tuple = `${getPlatform(platform)}_${getArch(arch)}`;
debug('Creating GOPATH directory structure for %o (%s)', goPath, tuple);
return Promise.all([
mkdirp(join(goPath, 'bin')),
mkdirp(join(goPath, 'pkg', tuple)),
]);
}
async function get({ src } = {}) {
const args = ['get'];
if (src) {
debug('Fetching `go` dependencies for file %o', src);
args.push(src);
} else {
debug('Fetching `go` dependencies for cwd %o', this.cwd);
}
await this(...args);
}
async function build({ src, dest }) {
debug('Building `go` binary %o -> %o', src, dest);
let sources;
if (Array.isArray(src)) {
sources = src;
} else {
sources = [src];
}
await this('build', '-o', dest, ...sources);
}
async function createGo(
goPath,
platform = process.platform,
arch = process.arch,
opts = {},
goMod = false,
) {
const env = {
...process.env,
PATH: `${dirname(GO_BIN)}:${process.env.PATH}`,
GOPATH: goPath,
...opts.env,
};
if (goMod) {
env.GO111MODULE = 'on';
}
function go(...args) {
debug('Exec %o', `go ${args.join(' ')}`);
return execa('go', args, { stdio: 'inherit', ...opts, env });
}
go.cwd = opts.cwd || process.cwd();
go.get = get;
go.build = build;
go.goPath = goPath;
await createGoPathTree(goPath, platform, arch);
return go;
}
async function downloadGo(
dir = GO_DIR,
version = '1.12',
platform = process.platform,
arch = process.arch,
) {
debug('Installing `go` v%s to %o for %s %s', version, dir, platform, arch);
const url = getGoUrl(version, platform, arch);
debug('Downloading `go` URL: %o', url);
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to download: ${url} (${res.status})`);
}
// TODO: use a zip extractor when `ext === "zip"`
await mkdirp(dir);
await new Promise((resolve, reject) => {
res.body
.on('error', reject)
.pipe(tar.extract({ cwd: dir, strip: 1 }))
.on('error', reject)
.on('finish', resolve);
});
return createGo(dir, platform, arch);
}
module.exports = {
createGo,
downloadGo,
getExportedFunctionName,
};

View File

@@ -0,0 +1,151 @@
import tar from 'tar';
import execa from 'execa';
import fetch from 'node-fetch';
import { mkdirp, pathExists } from 'fs-extra';
import { dirname, join } from 'path';
import Debug from 'debug';
const debug = Debug('@now/go:go-helpers');
const archMap = new Map([['x64', 'amd64'], ['x86', '386']]);
const platformMap = new Map([['win32', 'windows']]);
// Location where the `go` binary will be installed after `postinstall`
const GO_DIR = join(__dirname, 'go');
const GO_BIN = join(GO_DIR, 'bin/go');
const getPlatform = (p: string) => platformMap.get(p) || p;
const getArch = (a: string) => archMap.get(a) || a;
const getGoUrl = (version: string, platform: string, arch: string) => {
const goArch = getArch(arch);
const goPlatform = getPlatform(platform);
const ext = platform === 'win32' ? 'zip' : 'tar.gz';
return `https://dl.google.com/go/go${version}.${goPlatform}-${goArch}.${ext}`;
};
export async function getAnalyzedEntrypoint(filePath: string) {
debug('Analyzing entrypoint %o', filePath);
const bin = join(__dirname, 'analyze');
const isAnalyzeExist = await pathExists(bin);
if (!isAnalyzeExist) {
const src = join(__dirname, 'util', 'analyze.go');
const dest = join(__dirname, 'analyze');
const go = await downloadGo();
await go.build(src, dest);
}
const args = [filePath];
const analyzed = await execa.stdout(bin, args);
debug('Analyzed entrypoint %o', analyzed);
return analyzed;
}
// Creates a `$GOPATH` directory tree, as per `go help gopath` instructions.
// Without this, `go` won't recognize the `$GOPATH`.
function createGoPathTree(goPath: string, platform: string, arch: string) {
const tuple = `${getPlatform(platform)}_${getArch(arch)}`;
debug('Creating GOPATH directory structure for %o (%s)', goPath, tuple);
return Promise.all([
mkdirp(join(goPath, 'bin')),
mkdirp(join(goPath, 'pkg', tuple)),
]);
}
class GoWrapper {
private env: { [key: string]: string };
private opts: execa.Options;
constructor(env: { [key: string]: string }, opts: execa.Options = {}) {
if (!opts.cwd) {
opts.cwd = process.cwd();
}
this.env = env;
this.opts = opts;
}
private execute(...args: string[]) {
const { opts, env } = this;
debug('Exec %o', `go ${args.join(' ')}`);
return execa('go', args, { stdio: 'inherit', ...opts, env });
}
mod() {
return this.execute('mod', 'tidy');
}
get(src?: string) {
const args = ['get'];
if (src) {
debug('Fetching `go` dependencies for file %o', src);
args.push(src);
} else {
debug('Fetching `go` dependencies for cwd %o', this.opts.cwd);
}
return this.execute(...args);
}
build(src: string | string[], dest: string, ldsflags = '-s -w') {
debug('Building optimized `go` binary %o -> %o', src, dest);
const sources = Array.isArray(src) ? src : [src];
return this.execute('build', '-ldflags', ldsflags, '-o', dest, ...sources);
}
}
export async function createGo(
goPath: string,
platform = process.platform,
arch = process.arch,
opts: execa.Options = {},
goMod = false
) {
const path = `${dirname(GO_BIN)}:${process.env.PATH}`;
const env: { [key: string]: string } = {
...process.env,
PATH: path,
GOPATH: goPath,
...opts.env,
};
if (goMod) {
env.GO111MODULE = 'on';
}
await createGoPathTree(goPath, platform, arch);
return new GoWrapper(env, opts);
}
export async function downloadGo(
dir = GO_DIR,
version = '1.12',
platform = process.platform,
arch = process.arch
) {
debug('Installing `go` v%s to %o for %s %s', version, dir, platform, arch);
const url = getGoUrl(version, platform, arch);
// if we found GOPATH in ENV, use it
if (process.env.GOPATH !== undefined) {
return createGo(dir, platform, arch);
} else {
const isGoExist = await pathExists(join(dir, 'bin'));
if (!isGoExist) {
debug('Downloading `go` URL: %o', url);
console.log('Downloading Go ...');
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to download: ${url} (${res.status})`);
}
// TODO: use a zip extractor when `ext === "zip"`
await mkdirp(dir);
await new Promise((resolve, reject) => {
res.body
.on('error', reject)
.pipe(tar.extract({ cwd: dir, strip: 1 }))
.on('error', reject)
.on('finish', resolve);
});
}
return createGo(dir, platform, arch);
}
}

View File

@@ -1,52 +1,97 @@
const { join, sep, dirname } = require('path');
const {
readFile, writeFile, pathExists, move,
} = require('fs-extra');
import { join, sep, dirname } from 'path';
import { readFile, writeFile, pathExists, move } from 'fs-extra';
const glob = require('@now/build-utils/fs/glob.js'); // eslint-disable-line import/no-extraneous-dependencies
const download = require('@now/build-utils/fs/download.js'); // eslint-disable-line import/no-extraneous-dependencies
const { createLambda } = require('@now/build-utils/lambda.js'); // eslint-disable-line import/no-extraneous-dependencies
const getWritableDirectory = require('@now/build-utils/fs/get-writable-directory.js'); // eslint-disable-line import/no-extraneous-dependencies
const { createGo, getExportedFunctionName } = require('./go-helpers');
import {
glob,
download,
createLambda,
getWriteableDirectory,
BuildOptions,
shouldServe,
Files,
} from '@now/build-utils';
const config = {
import { createGo, getAnalyzedEntrypoint } from './go-helpers';
interface Analyzed {
packageName: string;
functionName: string;
watch: string[];
}
interface BuildParamsMeta {
isDev: boolean | undefined;
}
interface BuildParamsType extends BuildOptions {
files: Files;
entrypoint: string;
workPath: string;
meta: BuildParamsMeta;
}
export const version = 2;
export const config = {
maxLambdaSize: '10mb',
};
async function build({ files, entrypoint }) {
export async function build({
files,
entrypoint,
config,
meta = {} as BuildParamsMeta,
}: BuildParamsType) {
console.log('Downloading user files...');
const entrypointArr = entrypoint.split(sep);
const [goPath, outDir] = await Promise.all([
getWritableDirectory(),
getWritableDirectory(),
let [goPath, outDir] = await Promise.all([
getWriteableDirectory(),
getWriteableDirectory(),
]);
if (meta.isDev) {
const devGoPath = `dev${entrypointArr[entrypointArr.length - 1]}`;
const goPathArr = goPath.split(sep);
goPathArr.pop();
goPathArr.push(devGoPath);
goPath = goPathArr.join(sep);
}
const srcPath = join(goPath, 'src', 'lambda');
const downloadedFiles = await download(files, srcPath);
const input = dirname(downloadedFiles[entrypoint].fsPath);
var includedFiles: Files = {};
if (config && config.includeFiles) {
for (const pattern of config.includeFiles) {
const files = await glob(pattern, input);
for (const assetName of Object.keys(files)) {
includedFiles[assetName] = files[assetName];
}
}
}
console.log(`Parsing AST for "${entrypoint}"`);
let parseFunctionName;
let analyzed: string;
try {
parseFunctionName = await getExportedFunctionName(
downloadedFiles[entrypoint].fsPath,
);
analyzed = await getAnalyzedEntrypoint(downloadedFiles[entrypoint].fsPath);
} catch (err) {
console.log(`Failed to parse AST for "${entrypoint}"`);
throw err;
}
if (!parseFunctionName) {
if (!analyzed) {
const err = new Error(
`Could not find an exported function in "${entrypoint}"`,
`Could not find an exported function in "${entrypoint}"`
);
console.log(err.message);
throw err;
}
const handlerFunctionName = parseFunctionName.split(',')[0];
const parsedAnalyzed = JSON.parse(analyzed) as Analyzed;
const handlerFunctionName = parsedAnalyzed.functionName;
console.log(
`Found exported function "${handlerFunctionName}" in "${entrypoint}"`,
`Found exported function "${handlerFunctionName}" in "${entrypoint}"`
);
// we need `main.go` in the same dir as the entrypoint,
@@ -54,7 +99,7 @@ async function build({ files, entrypoint }) {
const entrypointDirname = dirname(downloadedFiles[entrypoint].fsPath);
// check if package name other than main
const packageName = parseFunctionName.split(',')[1];
const packageName = parsedAnalyzed.packageName;
const isGoModExist = await pathExists(join(entrypointDirname, 'go.mod'));
if (packageName !== 'main') {
const go = await createGo(
@@ -64,7 +109,7 @@ async function build({ files, entrypoint }) {
{
cwd: entrypointDirname,
},
true,
true
);
if (!isGoModExist) {
try {
@@ -80,7 +125,7 @@ async function build({ files, entrypoint }) {
const mainModGoFileName = 'main__mod__.go';
const modMainGoContents = await readFile(
join(__dirname, mainModGoFileName),
'utf8',
'utf8'
);
let goPackageName = `${packageName}/${packageName}`;
@@ -89,11 +134,10 @@ async function build({ files, entrypoint }) {
if (isGoModExist) {
const goModContents = await readFile(
join(entrypointDirname, 'go.mod'),
'utf8',
'utf8'
);
goPackageName = `${
goModContents.split('\n')[0].split(' ')[1]
}/${packageName}`;
const usrModName = goModContents.split('\n')[0].split(' ')[1];
goPackageName = `${usrModName}/${packageName}`;
}
const mainModGoContents = modMainGoContents
@@ -103,34 +147,56 @@ async function build({ files, entrypoint }) {
// write main__mod__.go
await writeFile(
join(entrypointDirname, mainModGoFileName),
mainModGoContents,
mainModGoContents
);
// move user go file to folder
try {
// default path
let finalDestination = join(entrypointDirname, packageName, entrypoint);
const entrypointArr = entrypoint.split(sep);
let forceMove = false;
if (meta.isDev) {
forceMove = true;
}
// if `entrypoint` include folder, only use filename
if (entrypointArr.length > 1) {
finalDestination = join(
entrypointDirname,
packageName,
entrypointArr.pop(),
entrypointArr[entrypointArr.length - 1]
);
}
await move(downloadedFiles[entrypoint].fsPath, finalDestination);
await move(downloadedFiles[entrypoint].fsPath, finalDestination, {
overwrite: forceMove,
});
} catch (err) {
console.log('failed to move entry to package folder');
throw err;
}
console.log('tidy go.mod file');
if (meta.isDev) {
const isGoModBk = await pathExists(join(entrypointDirname, 'go.mod.bk'));
if (isGoModBk) {
await move(
join(entrypointDirname, 'go.mod.bk'),
join(entrypointDirname, 'go.mod'),
{ overwrite: true }
);
await move(
join(entrypointDirname, 'go.sum.bk'),
join(entrypointDirname, 'go.sum'),
{ overwrite: true }
);
}
}
console.log('Tidy `go.mod` file...');
try {
// ensure go.mod up-to-date
await go('mod', 'tidy');
await go.mod();
} catch (err) {
console.log('failed to `go mod tidy`');
throw err;
@@ -140,11 +206,24 @@ async function build({ files, entrypoint }) {
const destPath = join(outDir, 'handler');
try {
const src = [join(entrypointDirname, mainModGoFileName)];
await go.build({ src, dest: destPath });
await go.build(src, destPath, config.ldsflags);
} catch (err) {
console.log('failed to `go build`');
throw err;
}
if (meta.isDev) {
// caching for `now dev`
await move(
join(entrypointDirname, 'go.mod'),
join(entrypointDirname, 'go.mod.bk'),
{ overwrite: true }
);
await move(
join(entrypointDirname, 'go.sum'),
join(entrypointDirname, 'go.sum.bk'),
{ overwrite: true }
);
}
} else {
const go = await createGo(
goPath,
@@ -153,15 +232,15 @@ async function build({ files, entrypoint }) {
{
cwd: entrypointDirname,
},
false,
false
);
const origianlMainGoContents = await readFile(
join(__dirname, 'main.go'),
'utf8',
'utf8'
);
const mainGoContents = origianlMainGoContents.replace(
'__NOW_HANDLER_FUNC_NAME',
handlerFunctionName,
handlerFunctionName
);
// in order to allow the user to have `main.go`,
@@ -174,6 +253,7 @@ async function build({ files, entrypoint }) {
// `go get` will look at `*.go` (note we set `cwd`), parse the `import`s
// and download any packages that aren't part of the stdlib
console.log('Running `go get`...');
try {
await go.get();
} catch (err) {
@@ -188,7 +268,7 @@ async function build({ files, entrypoint }) {
join(entrypointDirname, mainGoFileName),
downloadedFiles[entrypoint].fsPath,
];
await go.build({ src, dest: destPath });
await go.build(src, destPath);
} catch (err) {
console.log('failed to `go build`');
throw err;
@@ -196,15 +276,27 @@ async function build({ files, entrypoint }) {
}
const lambda = await createLambda({
files: await glob('**', outDir),
files: { ...(await glob('**', outDir)), ...includedFiles },
handler: 'handler',
runtime: 'go1.x',
environment: {},
});
const output = {
[entrypoint]: lambda,
};
let watch = parsedAnalyzed.watch;
// if `entrypoint` located in subdirectory
// we will need to concat it with return watch array
if (entrypointArr.length > 1) {
entrypointArr.pop();
watch = parsedAnalyzed.watch.map(file => join(...entrypointArr, file));
}
return {
[entrypoint]: lambda,
output,
watch,
};
}
module.exports = { config, build };
export { shouldServe };

View File

@@ -1,6 +1,6 @@
{
"name": "@now/go",
"version": "0.4.0",
"version": "0.4.3-canary.0",
"license": "MIT",
"repository": {
"type": "git",
@@ -8,7 +8,9 @@
"directory": "packages/now-go"
},
"scripts": {
"postinstall": "node ./util/install"
"build": "tsc",
"test": "tsc && jest",
"prepublish": "tsc"
},
"files": [
"*.js",
@@ -20,8 +22,15 @@
"debug": "^4.1.1",
"execa": "^1.0.0",
"fs-extra": "^7.0.0",
"mkdirp-promise": "5.0.1",
"node-fetch": "^2.2.1",
"tar": "4.4.6"
},
"devDependencies": {
"@types/debug": "^4.1.3",
"@types/execa": "^0.9.0",
"@types/fs-extra": "^5.0.5",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"typescript": "^3.4.2"
}
}

View File

@@ -0,0 +1 @@
module build-env

View File

@@ -0,0 +1,17 @@
package buildenv
import (
"fmt"
"net/http"
"os"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_BUILD_ENV")
if rdm == "" {
fmt.Println("No build env received")
}
fmt.Fprintf(w, rdm+":build-env")
}

View File

@@ -0,0 +1 @@
module env

View File

@@ -0,0 +1,17 @@
package env
import (
"fmt"
"net/http"
"os"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_ENV")
if rdm == "" {
fmt.Println("No env received")
}
fmt.Fprintf(w, rdm)
}

View File

@@ -0,0 +1,18 @@
{
"version": 2,
"builds": [
{
"src": "env/index.go",
"use": "@now/go"
}
],
"env": {
"RANDOMNESS_ENV": "RANDOMNESS_PLACEHOLDER"
},
"probes": [
{
"path": "/env",
"mustContain": "RANDOMNESS_PLACEHOLDER"
}
]
}

View File

@@ -0,0 +1,11 @@
package function
import (
"fmt"
"net/http"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "RANDOMNESS_PLACEHOLDER")
}

View File

@@ -0,0 +1,6 @@
{
"version": 2,
"builds": [
{ "src": "index.go", "use": "@now/go" }
]
}

View File

@@ -0,0 +1,9 @@
{
"version": 2,
"builds": [
{ "src": "*.go", "use": "@now/go" }
],
"env": {
"RANDOMNESS_ENV_VAR": "RANDOMNESS_PLACEHOLDER"
}
}

View File

@@ -0,0 +1,16 @@
package function
import (
"net/http"
"os"
"strconv"
)
// HandlerTest1 function
func HandlerTest1(w http.ResponseWriter, r *http.Request) {
rdm := os.Getenv("RANDOMNESS_ENV_VAR")
w.WriteHeader(401)
w.Header().Set("content-length", strconv.Itoa(len(rdm+":content-length")))
w.Write([]byte(rdm + ":content-length"))
}

View File

@@ -0,0 +1,12 @@
package function
import (
"net/http"
)
// HandlerTest2 function
func HandlerTest2(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Length", "2")
w.WriteHeader(401)
w.Write([]byte(""))
}

View File

@@ -0,0 +1,13 @@
package function
import (
"net/http"
"os"
)
// HandlerTest3 function
func HandlerTest3(w http.ResponseWriter, r *http.Request) {
rev := os.Getenv("RANDOMNESS_ENV_VAR")
w.WriteHeader(401)
w.Write([]byte(rev + ":content-length"))
}

View File

@@ -0,0 +1,16 @@
package cowsay
import (
"fmt"
"io/ioutil"
"net/http"
)
// Handler function
func Handler(w http.ResponseWriter, r *http.Request) {
bts, err := ioutil.ReadFile("templates/foo.txt")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
fmt.Fprintf(w, string(bts))
}

View File

@@ -0,0 +1,20 @@
{
"version": 2,
"builds": [
{
"src": "index.go",
"use": "@now/go",
"config": {
"includeFiles": [
"templates/**"
]
}
}
],
"probes": [
{
"path": "/",
"mustContain": "foobar from file"
}
]
}

View File

@@ -0,0 +1 @@
foobar from file

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"declaration": false,
"esModuleInterop": true,
"lib": ["esnext"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitThis": false,
"types": ["node"],
"strict": true,
"target": "esnext"
}
}

View File

@@ -0,0 +1,161 @@
package main
import (
"encoding/json"
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
type analyze struct {
PackageName string `json:"packageName"`
FuncName string `json:"functionName"`
Watch []string `json:"watch"`
}
// parse go file
func parse(fileName string) *ast.File {
fset := token.NewFileSet()
parsed, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
if err != nil {
log.Fatalf("Could not parse Go file \"%s\"\n", fileName)
os.Exit(1)
}
return parsed
}
// ensure we only working with interest go file(s)
func visit(files *[]string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
itf, err := filepath.Match("*test.go", path)
if err != nil {
log.Fatal(err)
}
// we don't need Dirs, or test files
// we only want `.go` files
if info.IsDir() || itf || filepath.Ext(path) != ".go" {
return nil
}
*files = append(*files, path)
return nil
}
}
// return unique file
func unique(files []string) []string {
encountered := map[string]bool{}
for v := range files {
encountered[files[v]] = true
}
result := []string{}
for key := range encountered {
result = append(result, key)
}
return result
}
func main() {
if len(os.Args) != 2 {
// Args should have the program name on `0`
// and the file name on `1`
fmt.Println("Wrong number of args; Usage is:\n ./go-analyze file_name.go")
os.Exit(1)
}
fileName := os.Args[1]
rf, err := ioutil.ReadFile(fileName)
if err != nil {
log.Fatal(err)
}
se := string(rf)
var files []string
var relatedFiles []string
// Add entrypoint to watchlist
relFileName, err := filepath.Rel(filepath.Dir(fileName), fileName)
if err != nil {
log.Fatal(err)
}
relatedFiles = append(relatedFiles, relFileName)
// looking for all go files that have export func
// using in entrypoint
err = filepath.Walk(filepath.Dir(fileName), visit(&files))
if err != nil {
log.Fatal(err)
}
for _, file := range files {
absFileName, _ := filepath.Abs(fileName)
absFile, _ := filepath.Abs(file)
// if it isn't entrypoint
if absFileName != absFile {
// find all export structs and functions
pf := parse(file)
var exportedDecl []string
ast.Inspect(pf, func(n ast.Node) bool {
switch t := n.(type) {
case *ast.FuncDecl:
if t.Name.IsExported() {
exportedDecl = append(exportedDecl, t.Name.Name)
}
// find variable declarations
case *ast.TypeSpec:
// which are public
if t.Name.IsExported() {
switch t.Type.(type) {
// and are interfaces
case *ast.StructType:
exportedDecl = append(exportedDecl, t.Name.Name)
}
}
}
return true
})
for _, ed := range exportedDecl {
if strings.Contains(se, ed) {
// find relative path of related file
rel, err := filepath.Rel(filepath.Dir(fileName), file)
if err != nil {
log.Fatal(err)
}
relatedFiles = append(relatedFiles, rel)
}
}
}
}
parsed := parse(fileName)
for _, decl := range parsed.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok {
// this declaraction is not a function
// so we're not interested
continue
}
if fn.Name.IsExported() == true {
// we found the first exported function
// we're done!
analyzed := analyze{
PackageName: parsed.Name.Name,
FuncName: fn.Name.Name,
Watch: unique(relatedFiles),
}
json, _ := json.Marshal(analyzed)
fmt.Print(string(json))
os.Exit(0)
}
}
}

View File

@@ -1,41 +0,0 @@
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
)
func main() {
if len(os.Args) != 2 {
// Args should have the program name on `0`
// and the file name on `1`
fmt.Println("Wrong number of args; Usage is:\n ./get-exported-function-name file_name.go")
os.Exit(1)
}
fileName := os.Args[1]
fset := token.NewFileSet()
parsed, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
if err != nil {
fmt.Printf("Could not parse Go file \"%s\"\n", fileName)
os.Exit(1)
}
for _, decl := range parsed.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok {
// this declaraction is not a function
// so we're not interested
continue
}
if fn.Name.IsExported() == true {
// we found the first exported function
// we're done!
fmt.Print(fn.Name.Name, ",", parsed.Name.Name)
os.Exit(0)
}
}
}

View File

@@ -1,18 +0,0 @@
const { join } = require('path');
const { downloadGo } = require('../go-helpers');
async function main() {
// First download the `go` binary for this platform/arch.
const go = await downloadGo();
// Build the `get-exported-function-name` helper program.
// `go get` is not necessary because the program has no external deps.
const src = join(__dirname, 'get-exported-function-name.go');
const dest = join(__dirname, '../get-exported-function-name');
await go.build({ src, dest });
}
main().catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -1,6 +1,6 @@
{
"name": "@now/next",
"version": "0.2.0",
"version": "0.2.1-canary.0",
"license": "MIT",
"main": "./dist/index",
"scripts": {

View File

@@ -3,17 +3,13 @@ import { parse } from 'url';
import getPort from 'get-port';
import { createServer } from 'http';
export interface ProcessEnv {
[key: string]: string;
}
async function main(env: ProcessEnv, cwd: string) {
async function main(cwd: string) {
const next = require(resolveFrom(cwd, 'next'));
const app = next({ dev: true, dir: cwd });
const handler = app.getRequestHandler();
const openPort = await getPort({
port: [ 5000, 4000 ]
port: [5000, 4000],
});
const url = `http://localhost:${openPort}`;
@@ -24,18 +20,11 @@ async function main(env: ProcessEnv, cwd: string) {
createServer((req, res) => {
const parsedUrl = parse(req.url || '', true);
handler(req, res, parsedUrl);
}).listen(openPort, (error: NodeJS.ErrnoException) => {
if (error) {
console.error(error);
process.exit(1);
return;
}
}).listen(openPort, () => {
if (process.send) {
process.send(url);
}
});
}
main(process.env as ProcessEnv, process.cwd());
main(process.cwd());

View File

@@ -120,12 +120,11 @@ const name = '[@now/next]';
const urls: stringMap = {};
function startDevServer(entryPath: string) {
// `env` is omitted since that
// makes it default to `process.env`
const forked = fork(path.join(__dirname, 'dev-server.js'), [], {
cwd: entryPath,
execArgv: [],
env: {
NOW_REGION: 'dev1',
},
});
const getUrl = () =>

View File

@@ -1,6 +1,6 @@
{
"name": "@now/node-server",
"version": "0.6.0",
"version": "0.6.1-canary.0",
"license": "MIT",
"repository": {
"type": "git",
@@ -9,7 +9,7 @@
},
"dependencies": {
"@now/node-bridge": "^1.1.0",
"@zeit/ncc": "0.18.1",
"@zeit/ncc": "0.18.2",
"fs-extra": "7.0.1"
},
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@now/node",
"version": "0.6.0",
"version": "0.6.1-canary.0",
"license": "MIT",
"main": "./dist/index",
"repository": {
@@ -10,7 +10,7 @@
},
"dependencies": {
"@now/node-bridge": "^1.1.0",
"@zeit/ncc": "0.18.1",
"@zeit/ncc": "0.18.2",
"fs-extra": "7.0.1"
},
"scripts": {

View File

@@ -1,31 +1,4 @@
import { join } from 'path';
import fetch from 'node-fetch';
import execa from 'execa';
import { createWriteStream } from 'fs';
import { getWriteableDirectory } from '@now/build-utils';
const url = 'https://bootstrap.pypa.io/get-pip.py';
// downloads `get-pip.py` and returns its absolute path
async function downloadGetPipScript() {
console.log('downloading "get-pip.py"...');
const res = await fetch(url);
if (!res.ok || res.status !== 200) {
throw new Error(`Could not download "get-pip.py" from "${url}"`);
}
const dir = await getWriteableDirectory();
const filePath = join(dir, 'get-pip.py');
const writeStream = createWriteStream(filePath);
return new Promise<string>((resolve, reject) => {
res.body
.on('error', reject)
.pipe(writeStream)
.on('finish', () => resolve(filePath));
});
}
// downloads and installs `pip` (respecting
// process.env.PYTHONUSERBASE), and returns
@@ -38,19 +11,38 @@ export async function downloadAndInstallPip() {
// is not set, and `~` is not writeable on AWS Lambda.
// let's refuse to proceed
throw new Error(
'Could not install "pip": "PYTHONUSERBASE" env var is not set',
'Could not install "pip": "PYTHONUSERBASE" env var is not set'
);
}
const getPipFilePath = await downloadGetPipScript();
console.log('running "python get-pip.py"...');
console.log('installing python...');
try {
await execa('python3', [getPipFilePath, '--user'], { stdio: 'inherit' });
await execa('uname', ['-a'], { stdio: 'inherit' });
await execa('yum-config-manager', ['--enable', 'epel'], {
stdio: 'inherit',
});
await execa(
'yum',
['install', '-y', 'https://centos6.iuscommunity.org/ius-release.rpm'],
{ stdio: 'inherit' }
);
//await execa('yum', ['update'], { stdio: 'inherit' });
await execa(
'yum',
[
'install',
'-y',
'python36u',
'python36u-libs',
'python36u-devel',
'python36u-pip',
],
{ stdio: 'inherit' }
);
} catch (err) {
console.log('could not install pip');
console.log('could not install python');
throw err;
}
return join(PYTHONUSERBASE, 'bin', 'pip');
return '/usr/bin/pip3.6';
}

View File

@@ -15,14 +15,24 @@ import { downloadAndInstallPip } from './download-and-install-pip';
async function pipInstall(pipPath: string, workDir: string, ...args: string[]) {
const target = '.';
console.log(`running "pip install --target ${target} --upgrade ${args.join(' ')}"...`);
console.log(
`running "pip install --target ${target} --upgrade ${args.join(' ')}"...`
);
try {
await execa(pipPath, ['install', '--target', target, '--upgrade', ...args], {
cwd: workDir,
stdio: 'inherit',
});
await execa(
pipPath,
['install', '--target', target, '--upgrade', ...args],
{
cwd: workDir,
stdio: 'inherit',
}
);
} catch (err) {
console.log(`failed to run "pip install --target ${target} --upgrade ${args.join(' ')}"...`);
console.log(
`failed to run "pip install --target ${target} --upgrade ${args.join(
' '
)}"...`
);
throw err;
}
}
@@ -42,11 +52,10 @@ async function pipInstallUser(pipPath: string, ...args: string[]) {
async function pipenvInstall(pyUserBase: string, srcDir: string) {
console.log('running "pipenv_to_requirements -f');
try {
await execa(
join(pyUserBase, 'bin', 'pipenv_to_requirements'),
['-f'],
{ cwd: srcDir, stdio: 'inherit' },
);
await execa(join(pyUserBase, 'bin', 'pipenv_to_requirements'), ['-f'], {
cwd: srcDir,
stdio: 'inherit',
});
} catch (err) {
console.log('failed to run "pipenv_to_requirements -f"');
throw err;
@@ -57,7 +66,12 @@ export const config = {
maxLambdaSize: '5mb',
};
export const build = async ({ workPath, files, entrypoint }: BuildOptions) => {
export const build = async ({
workPath,
files,
entrypoint,
meta = {},
}: BuildOptions) => {
console.log('downloading files...');
// eslint-disable-next-line no-param-reassign
@@ -67,7 +81,7 @@ export const build = async ({ workPath, files, entrypoint }: BuildOptions) => {
// we need it to be under `/tmp`
const pyUserBase = await getWriteableDirectory();
process.env.PYTHONUSERBASE = pyUserBase;
const pipPath = await downloadAndInstallPip();
const pipPath = meta.isDev ? 'pip3' : await downloadAndInstallPip();
try {
// See: https://stackoverflow.com/a/44728772/376773
@@ -122,7 +136,7 @@ export const build = async ({ workPath, files, entrypoint }: BuildOptions) => {
.replace(/\.py$/, '');
const nowHandlerPyContents = originalNowHandlerPyContents.replace(
/__NOW_HANDLER_FILENAME/g,
userHandlerFilePath,
userHandlerFilePath
);
// in order to allow the user to have `server.py`, we need our `server.py` to be called
@@ -131,7 +145,7 @@ export const build = async ({ workPath, files, entrypoint }: BuildOptions) => {
await writeFile(
join(workPath, `${nowHandlerPyFilename}.py`),
nowHandlerPyContents,
nowHandlerPyContents
);
const lambda = await createLambda({

View File

@@ -1,6 +1,6 @@
{
"name": "@now/python",
"version": "0.1.0",
"version": "0.1.1-canary.0",
"main": "index.js",
"license": "MIT",
"repository": {

View File

@@ -1,9 +1,8 @@
const path = require('path');
const { spawn } = require('child_process');
const getPort = require('get-port');
const { promisify } = require('util');
const { timeout } = require('promise-timeout');
const { existsSync, readFileSync } = require('fs');
const waitForPort = promisify(require('wait-for-port'));
const {
glob,
download,
@@ -16,7 +15,7 @@ function validateDistDir(distDir) {
const distDirName = path.basename(distDir);
if (!existsSync(distDir)) {
const message = `Build was unable to create the distDir: ${distDirName}.`
+ '\nMake sure you mentioned the correct dist directory: https://zeit.co/docs/v2/deployments/official-builders/static-build-now-static-build/#configuring-the-build-output-directory';
+ '\nMake sure you mentioned the correct dist directory: https://zeit.co/docs/v2/deployments/official-builders/static-build-now-static-build/#local-development';
throw new Error(message);
}
}
@@ -61,26 +60,31 @@ exports.build = async ({
const opts = {
env: { ...process.env, PORT: String(devPort) },
};
const promise = runPackageJsonScript(
entrypointFsDirname,
'now-dev',
opts,
);
promise.then(
() => {
nowDevScriptPorts.delete(entrypoint);
},
(err) => {
console.log('`now-dev` script error:', err);
nowDevScriptPorts.delete(entrypoint);
},
);
const child = spawn('yarn', ['run', 'now-dev'], opts);
child.on('exit', () => nowDevScriptPorts.delete(entrypoint));
child.stdout.setEncoding('utf8');
child.stdout.pipe(process.stdout);
child.stderr.setEncoding('utf8');
child.stderr.pipe(process.stderr);
// Now wait for the server to have listened on `$PORT`, after which we
// will ProxyPass any requests to that development server that come in
// for this builder.
try {
await timeout(waitForPort('localhost', devPort), 60 * 1000);
await timeout(
new Promise((resolve) => {
const checkForPort = (data) => {
// Check the logs for the URL being printed with the port number
// (i.e. `http://localhost:47521`).
if (data.indexOf(`:${devPort}`) !== -1) {
resolve();
}
};
child.stdout.on('data', checkForPort);
child.stderr.on('data', checkForPort);
}),
5 * 60 * 1000,
);
} catch (err) {
throw new Error(
`Failed to detect a server running on port ${devPort}`,
@@ -99,6 +103,12 @@ exports.build = async ({
dest: `http://localhost:${devPort}${srcBase}/$1`,
});
} else {
if (meta.isDev) {
console.log('WARN: "now-dev" script is missing from package.json');
console.log(
'See the local development docs: http://zeit.co/docs/v2/deployments/official-builders/static-now-static#local-development',
);
}
// Run the `now-build` script and wait for completion to collect the build
// outputs
console.log('running user "now-build" script from `package.json`...');

View File

@@ -1,6 +1,6 @@
{
"name": "@now/static-build",
"version": "0.5.0",
"version": "0.5.3-canary.0",
"license": "MIT",
"repository": {
"type": "git",
@@ -12,7 +12,6 @@
},
"dependencies": {
"get-port": "5.0.0",
"promise-timeout": "1.3.0",
"wait-for-port": "0.0.2"
"promise-timeout": "1.3.0"
}
}

View File

@@ -940,6 +940,18 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/cross-spawn@6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.0.tgz#320aaf1d1a12979f1b84fe7a5590a7e860bf3a80"
integrity sha512-evp2ZGsFw9YKprDbg8ySgC9NA15g3YgiI8ANkGmKKvvi0P2aDGYLPxQIC5qfeKNUOe3TjABVGuah6omPRpIYhg==
dependencies:
"@types/node" "*"
"@types/debug@^4.1.3":
version "4.1.4"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.4.tgz#56eec47706f0fd0b7c694eae2f3172e6b0b769da"
integrity sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==
"@types/end-of-stream@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@types/end-of-stream/-/end-of-stream-1.4.0.tgz#4e73ac87d15b6cc89cdaf2d26a59f617c778cb07"
@@ -1015,6 +1027,13 @@
dependencies:
"@types/node" "*"
"@types/node-fetch@^2.3.0":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.3.2.tgz#e01893b176c6fa1367743726380d65bce5d6576b"
integrity sha512-yW0EOebSsQme9yKu09XbdDfle4/SmWZMK4dfteWcSLCYNQQcF+YOv0kIrvm+9pO11/ghA4E6A+RNQqvYj4Nr3A==
dependencies:
"@types/node" "*"
"@types/node@*", "@types/node@^10.12.8":
version "10.12.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.10.tgz#4fa76e6598b7de3f0cb6ec3abacc4f59e5b3a2ce"
@@ -1068,6 +1087,13 @@
resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370"
integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==
"@types/tar@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/tar/-/tar-4.0.0.tgz#e3239d969eeb693a012200613860d0eb871c94f0"
integrity sha512-YybbEHNngcHlIWVCYsoj7Oo1JU9JqONuAlt1LlTH/lmL8BMhbzdFUgReY87a05rY1j8mfK47Del+TCkaLAXwLw==
dependencies:
"@types/node" "*"
"@types/uglify-js@*":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
@@ -1109,10 +1135,10 @@
globby "8.0.0"
signal-exit "3.0.2"
"@zeit/ncc@0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@zeit/ncc/-/ncc-0.18.1.tgz#1723884210c792ba702ec6dccb390f387f0a3ba6"
integrity sha512-Tq13BzK+hAWBZY+VvncRZzpE5PHGks3kn2XJ+bcWSXgTZb4rTR/CTV1YYXilNNkX//jC1sziuM167FhLzFu2XA==
"@zeit/ncc@0.18.2":
version "0.18.2"
resolved "https://registry.yarnpkg.com/@zeit/ncc/-/ncc-0.18.2.tgz#b5f721ec1d23bfe531f3568633689ddab7c05638"
integrity sha512-liiuVTcxLaOIGQDftpZ2qhSS/vdEbuvmi2tkBWMfIwIyeKd/sh/jw+l8yONT3/unx/sSmfMTDnwfwUlY+saKiw==
JSONStream@^1.0.4, JSONStream@^1.3.4:
version "1.3.5"
@@ -2515,16 +2541,7 @@ create-error-class@^3.0.1:
dependencies:
capture-stack-trace "^1.0.0"
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
dependencies:
lru-cache "^4.0.1"
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
@@ -2535,6 +2552,15 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
dependencies:
lru-cache "^4.0.1"
shebang-command "^1.2.0"
which "^1.2.9"
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
version "0.3.4"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797"
@@ -7003,14 +7029,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
mkdirp-promise@5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1"
integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=
dependencies:
mkdirp "*"
mkdirp@*, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0:
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
@@ -9605,6 +9624,11 @@ typescript@3.3.4000:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.4000.tgz#76b0f89cfdbf97827e1112d64f283f1151d6adf0"
integrity sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==
typescript@^3.4.2:
version "3.4.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.4.tgz#aac4a08abecab8091a75f10842ffa0631818f785"
integrity sha512-xt5RsIRCEaf6+j9AyOBgvVuAec0i92rgCaS3S+UVf5Z/vF2Hvtsw08wtUTJqp4djwznoAgjSxeCcU4r+CcDBJA==
typescript@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3.tgz#0eb320e4ace9b10eadf5bc6103286b0f8b7c224f"
@@ -9949,11 +9973,6 @@ w3c-hr-time@^1.0.1:
dependencies:
browser-process-hrtime "^0.1.2"
wait-for-port@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wait-for-port/-/wait-for-port-0.0.2.tgz#bb5ff253436b9933ab9d65c00d584dc68c4d531a"
integrity sha1-u1/yU0NrmTOrnWXADVhNxoxNUxo=
walker@^1.0.7, walker@~1.0.5:
version "1.0.7"
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"