Skip to content

Fatal error when trying to deploy single-functions #161

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
AndrewFarley opened this issue Mar 14, 2018 · 16 comments · Fixed by #180
Closed

Fatal error when trying to deploy single-functions #161

AndrewFarley opened this issue Mar 14, 2018 · 16 comments · Fixed by #180
Labels

Comments

@AndrewFarley
Copy link
Contributor

AndrewFarley commented Mar 14, 2018

FYI: This is with the latest code from master
Version: serverless@1.26.1
Steps to reproduce: Create any/simple stack which uses this plugin, and try to do a single-function deploy.

  Error --------------------------------------------------
 
  Unsupported type: data is neither a path or a Buffer
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Stack Trace --------------------------------------------
 
Error: Unsupported type: data is neither a path or a Buffer
    at Object.ZipLocal.sync.unzip (/Users/farley/myService/node_modules/zip-local/main.js:386:15)
    at injectRequirements (/Users/farley/myService/node_modules/serverless-python-requirements/lib/inject.js:45:27)
    at ServerlessPythonRequirements.injectAllRequirements (/Users/farley/myService/node_modules/serverless-python-requirements/lib/inject.js:118:5)
From previous event:
    at PluginManager.invoke (/Users/farley/.npm-packages/lib/node_modules/serverless/lib/classes/PluginManager.js:372:22)
    at PluginManager.run (/Users/farley/.npm-packages/lib/node_modules/serverless/lib/classes/PluginManager.js:403:17)
    at variables.populateService.then (/Users/farley/.npm-packages/lib/node_modules/serverless/lib/Serverless.js:102:33)
    at runCallback (timers.js:672:20)
    at tryOnImmediate (timers.js:645:5)
    at processImmediate [as _immediateCallback] (timers.js:617:5)
From previous event:
    at Serverless.run (/Users/farley/.npm-packages/lib/node_modules/serverless/lib/Serverless.js:89:74)
    at serverless.init.then (/Users/farley/.npm-packages/lib/node_modules/serverless/bin/serverless:42:50)
# serverless.yml
service: myService

provider:
  name: aws
  runtime: python2.7

plugins:
  - serverless-python-requirements

custom: 
  pythonRequirements:
    dockerizePip: true

functions:
  hello:
    handler: handler.hello
# requirements.txt
requests

master/bleeding edge might not be ready yet, I was just developing something on top of it and ran into this.

Cheers!

@DHager
Copy link

DHager commented Apr 4, 2018

Encountered this issue today, also with SLS 1.26.1, plugin 4.0.0.

@DHager
Copy link

DHager commented Apr 4, 2018

Did a little more digging, it seems the plugin is trying to access the serverless.yml setting for package artifact which in my case is not specified, meaning that it tries to use an undefined value to find a zip file.

I do not know whether it is supposed to find the "whole project" zip-file (e.g. /dir/.serverless/servicename.zip) or just the function_name.zip that is generated along with sls deploy -f function_name.

@dschep
Copy link
Contributor

dschep commented Apr 4, 2018

How did I miss this bug before I released 4.0.0 😢

Weird that the tests pass since they only have 1 function and no package artifact specified.

It should be finding the "whole project" zip-file as you say @DHager, unless of course that package.individually is set.

dschep added a commit that referenced this issue Apr 4, 2018
@dschep
Copy link
Contributor

dschep commented Apr 4, 2018

Hey @AndrewFarley & @DHager did I miss something? I think 43e1404 should fail tests, but it doesn't.

@DHager
Copy link

DHager commented Apr 4, 2018

@dschep While both seem to trigger the same "after" handler from plugin-hooks, it looks like when running sls package the value this.serverless.service.package.artifact is correctly pointing to the "big zip file". In contrast, when running sls deploy -f funcname the artifact is undefined.

I suspect what's happening is that a non-null artifact value is a side-effect of the packaging step, which is skipped when doing partial deploys. Specifically this part of the core serverless app:

packageAll() {
  const zipFileName = `${this.serverless.service.service}.zip`;

  return this.resolveFilePathsAll().then(filePaths =>
    this.zipFiles(filePaths, zipFileName).then(filePath => {
      // only set the default artifact for backward-compatibility
      // when no explicit artifact is defined
      if (!this.serverless.service.package.artifact) {
        this.serverless.service.package.artifact = filePath;
        this.serverless.service.artifact = filePath;
      }
      return filePath;
    })
  );
},

@DHager
Copy link

DHager commented Apr 10, 2018

In other words, I think it boils down to "The service.package.artifact configuration value isn't reliable."

Possible approaches:

  • Plugin uses some other mechanism (?) to discover the target zip file path, one which also works for per-function deploys.
  • Plugin copies some of the logic from the core platform, and guesses the correct zip file path when an explicit value is not available.
  • Core platform changes to always backfill the value, so that it is accessible to plugins during other operations.
  • Core platform finds some other way to expose the ZIP path to all plugins doing per-function deploys.

@AndrewFarley
Copy link
Contributor Author

In other words, I think it boils down to "The service.package.artifact configuration value isn't reliable."

If that is really the case, we should submit a patch upstream instead of fixing our plugin. However, I just tested, and it seems this problem is only in the latest (4.0.0) version of this plugin, if I force-use a previous release this problem goes away, which means, it's something we can fix and/or something that broke in the latest release. I admit, it is really annoying to not be able to do single-function deploys assisting in more rapid development, so I hope someone can fix this soon. I'll get around to it eventually if no one else does.

@dschep
Copy link
Contributor

dschep commented Apr 10, 2018

I agree that an upstream patch is desirable @AndrewFarley. I asked over in the serverless-contrib slack if anyone had thoughts on it but got no responses 🤷‍♂️

@dschep
Copy link
Contributor

dschep commented Apr 10, 2018

Created an issue upstream ☝️

@AndrewFarley
Copy link
Contributor Author

So, upstream patches aside, this works fine right now with pre-4.0 of this plugin. So, to me that says there is something we can do right now without having to wait for them to fix this upstream, no?

@dschep
Copy link
Contributor

dschep commented Apr 10, 2018

Not without ditching the "inject deps directly into the zip" change made in 4.0. It worked before because this plugin wasn't touching the zip at all, it was making symlinks before serverless created the zip file.

@AndrewFarley
Copy link
Contributor Author

Ahh, didn't know that change happened in 4.0. Only started really diving in the code with 4.0 . :) . Thanks for clarifying

@dschep
Copy link
Contributor

dschep commented Apr 10, 2018

Yup. No worries 👍

dschep added a commit that referenced this issue Apr 23, 2018
dschep added a commit that referenced this issue Apr 23, 2018
dschep added a commit that referenced this issue Apr 26, 2018
* Better mixed runtime & function deploy handling

fixes #161 and fixes #179

* another tweak

* fix again?

* Fix corrupted zip archive in case of same module

* Do not try to install requirements for non-python runtime

* Fix lint

* format

* update test for merging #181

*  @AndrewFarley's fix

* huh. depcheck sucks.

* fixix syntax error
@alexandreesl
Copy link

The problem still exists on current plugin version, how to fix this?

@AndrewFarley
Copy link
Contributor Author

@alexandreesl This should be fixed in the latest version, as of 4.0.3 which came out before you commented. It seems to be fixed for me as well, and I was the original reporter of this bug. If you're still having this bug, can you share with us your serverless.yml and system information and any other details you think are relevant? Thanks!

@hrkfdn
Copy link

hrkfdn commented Jul 13, 2018

EDIT: #218 seems related

I am still encountering this on 4.1.0.

I am using dockerizePip and individual packaging. This is a node-python mixed project, with two Python modules and several other Node modules. Deploying the whole stack works fine.

Serverless: Load command run
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command create
Serverless: Load command install
Serverless: Load command package
Serverless: Load command deploy
Serverless: Load command deploy:function
Serverless: Load command deploy:list
Serverless: Load command deploy:list:functions
Serverless: Load command invoke
Serverless: Load command invoke:local
Serverless: Load command info
Serverless: Load command logs
Serverless: Load command login
Serverless: Load command logout
Serverless: Load command metrics
Serverless: Load command print
Serverless: Load command remove
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command slstats
Serverless: Load command plugin
Serverless: Load command plugin
Serverless: Load command plugin:install
Serverless: Load command plugin
Serverless: Load command plugin:uninstall
Serverless: Load command plugin
Serverless: Load command plugin:list
Serverless: Load command plugin
Serverless: Load command plugin:search
Serverless: Load command emit
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command offline
Serverless: Load command offline:start
Serverless: Load command graph
Serverless: Load command requirements
Serverless: Load command requirements:clean
Serverless: Load command requirements:install
Serverless: Invoke deploy
Serverless: Invoke deploy:function
Serverless: Installing requirements of search/requirements.txt in .serverless/search...
Serverless: Docker Image: lambci/lambda:build-python3.6
Serverless: Installing requirements of remote-update/requirements.txt in .serverless/remote-update...
Serverless: Docker Image: lambci/lambda:build-python3.6
Serverless: Invoke package:function
Serverless: Packaging function: remoteUpdate...
Serverless: Excluding development dependencies...
Serverless: Injecting required Python packages to package...
 
  Type Error ---------------------------------------------
 
  path must be a string or Buffer
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Stack Trace --------------------------------------------
 
TypeError: path must be a string or Buffer
    at fs.readFile (fs.js:358:11)
    at go$readFile (/home/henrik/git/pmi-storefinder-backend/node_modules/graceful-fs/graceful-fs.js:73:14)
    at Object.readFile (/home/henrik/git/pmi-storefinder-backend/node_modules/graceful-fs/graceful-fs.js:70:12)
    at Object.readFile (/home/henrik/git/pmi-storefinder-backend/node_modules/universalify/index.js:5:67)
    at moveModuleUp (/home/henrik/git/pmi-storefinder-backend/node_modules/serverless-python-requirements/lib/inject.js:58:6)
    at BbPromise.resolve.filter.map.map.func (/home/henrik/git/pmi-storefinder-backend/node_modules/serverless-python-requirements/lib/inject.js:103:18)
    at runCallback (timers.js:810:20)
    at tryOnImmediate (timers.js:768:5)
    at processImmediate [as _immediateCallback] (timers.js:745:5)
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com
 
  Your Environment Information -----------------------------
     OS:                     linux
     Node Version:           8.11.3
     Serverless Version:     1.28.0

npm ls

pmi-storefinder-backend@1.0.0 /home/henrik/git/pmi-storefinder-backend
├── @google/maps@0.3.1
├─┬ @turf/turf@4.7.3
│ ├─┬ @turf/along@4.7.3
│ │ ├── @turf/bearing@4.7.3 deduped
│ │ ├── @turf/destination@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/area@4.7.3
│ │ ├─┬ @mapbox/geojson-area@0.2.2
│ │ │ └── wgs84@0.0.0
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/bbox@4.7.3
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/bbox-clip@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── lineclip@1.1.5
│ ├─┬ @turf/bbox-polygon@4.7.3
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/bearing@4.7.3
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/bezier@4.7.3
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/boolean-clockwise@4.7.3
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/boolean-contains@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/boolean-point-on-line@4.7.3 deduped
│ │ ├── @turf/inside@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/boolean-crosses@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/inside@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-intersect@4.7.3 deduped
│ │ └── @turf/polygon-to-linestring@4.7.3 deduped
│ ├─┬ @turf/boolean-disjoint@4.7.3
│ │ ├── @turf/inside@4.7.3 deduped
│ │ ├── @turf/line-intersect@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── @turf/polygon-to-linestring@4.7.3 deduped
│ ├─┬ @turf/boolean-equal@4.7.3
│ │ ├── @turf/clean-coords@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └─┬ geojson-equality@0.1.6
│ │   └── deep-equal@1.0.1 deduped
│ ├─┬ @turf/boolean-overlap@4.7.3
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-intersect@4.7.3 deduped
│ │ ├── @turf/line-overlap@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── geojson-equality@0.1.6 deduped
│ ├─┬ @turf/boolean-point-on-line@4.7.3
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/boolean-within@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/boolean-point-on-line@4.7.3 deduped
│ │ ├── @turf/inside@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/buffer@4.7.4
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├─┬ @turf/center@4.7.1
│ │ │ ├─┬ @turf/bbox@4.7.1
│ │ │ │ └── @turf/meta@4.7.1 deduped
│ │ │ └── @turf/helpers@4.7.1 deduped
│ │ ├── @turf/helpers@4.7.1
│ │ ├── @turf/meta@4.7.1
│ │ ├─┬ @turf/projection@4.7.3
│ │ │ ├── @turf/clone@4.7.3 deduped
│ │ │ └── @turf/meta@4.7.4 deduped
│ │ ├─┬ d3-geo@1.10.0
│ │ │ └── d3-array@1.2.1
│ │ └── jsts@1.3.0
│ ├─┬ @turf/center@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/center-of-mass@4.7.3
│ │ ├── @turf/centroid@4.7.3 deduped
│ │ ├── @turf/convex@4.7.3 deduped
│ │ ├── @turf/explode@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/centroid@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/circle@4.7.3
│ │ ├── @turf/destination@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/clean-coords@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├── @turf/clone@4.7.3
│ ├─┬ @turf/clusters@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/clusters-dbscan@4.7.3
│ │ ├── @turf/clone@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── density-clustering@1.3.0
│ ├─┬ @turf/clusters-kmeans@4.7.3
│ │ ├── @turf/clone@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── skmeans@0.9.7
│ ├─┬ @turf/collect@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/inside@4.7.3 deduped
│ │ └─┬ rbush@2.0.2
│ │   └── quickselect@1.1.1
│ ├─┬ @turf/combine@4.7.3
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/concave@4.7.3
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/tin@4.7.3 deduped
│ │ └─┬ geojson-dissolve@3.1.0
│ │   ├── @turf/meta@3.14.0
│ │   ├─┬ geojson-flatten@0.2.2
│ │   │ ├─┬ concat-stream@1.6.2
│ │   │ │ ├── buffer-from@1.1.0
│ │   │ │ ├── inherits@2.0.3 deduped
│ │   │ │ ├─┬ readable-stream@2.3.6
│ │   │ │ │ ├── core-util-is@1.0.2 deduped
│ │   │ │ │ ├── inherits@2.0.3 deduped
│ │   │ │ │ ├── isarray@1.0.0 deduped
│ │   │ │ │ ├── process-nextick-args@2.0.0
│ │   │ │ │ ├── safe-buffer@5.1.2 deduped
│ │   │ │ │ ├─┬ string_decoder@1.1.1
│ │   │ │ │ │ └── safe-buffer@5.1.2 deduped
│ │   │ │ │ └── util-deprecate@1.0.2 deduped
│ │   │ │ └── typedarray@0.0.6
│ │   │ └── minimist@1.2.0
│ │   ├── geojson-linestring-dissolve@0.0.1
│ │   ├─┬ topojson-client@3.0.0
│ │   │ └── commander@2.15.1
│ │   └─┬ topojson-server@3.0.0
│ │     └── commander@2.15.1 deduped
│ ├─┬ @turf/convex@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └─┬ convex-hull@1.0.3
│ │   ├─┬ affine-hull@1.0.0
│ │   │ └─┬ robust-orientation@1.1.3
│ │   │   ├─┬ robust-scale@1.0.2
│ │   │   │ ├── two-product@1.0.2 deduped
│ │   │   │ └── two-sum@1.0.0
│ │   │   ├── robust-subtract@1.0.0
│ │   │   ├── robust-sum@1.0.0
│ │   │   └── two-product@1.0.2
│ │   ├─┬ incremental-convex-hull@1.0.1
│ │   │ ├── robust-orientation@1.1.3 deduped
│ │   │ └─┬ simplicial-complex@1.0.0
│ │   │   ├── bit-twiddle@1.0.2
│ │   │   └── union-find@1.0.2
│ │   └─┬ monotone-convex-hull-2d@1.0.1
│ │     └── robust-orientation@1.1.3 deduped
│ ├─┬ @turf/destination@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/difference@4.7.4
│ │ ├── @turf/area@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── jsts@1.3.0 deduped
│ ├─┬ @turf/dissolve@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/boolean-overlap@4.7.3 deduped
│ │ ├── @turf/union@4.7.3 deduped
│ │ ├── geojson-utils@1.1.0
│ │ ├── get-closest@0.0.4
│ │ └── rbush@2.0.2 deduped
│ ├─┬ @turf/distance@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/envelope@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ └── @turf/bbox-polygon@4.7.3 deduped
│ ├─┬ @turf/explode@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/flatten@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/flip@4.7.3
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/great-circle@4.7.3
│ │ └── @turf/invariant@4.7.3 deduped
│ ├── @turf/helpers@4.7.3
│ ├─┬ @turf/hex-grid@4.7.3
│ │ ├── @turf/distance@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/idw@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/centroid@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ └── @turf/square-grid@4.7.3 deduped
│ ├─┬ @turf/inside@4.7.3
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/interpolate@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/centroid@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/hex-grid@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/point-grid@4.7.3 deduped
│ │ ├── @turf/square-grid@4.7.3 deduped
│ │ └── @turf/triangle-grid@4.7.3 deduped
│ ├─┬ @turf/intersect@4.7.4
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/truncate@4.7.3 deduped
│ │ └── jsts@1.3.0 deduped
│ ├── @turf/invariant@4.7.3
│ ├─┬ @turf/isobands@4.7.3
│ │ ├─┬ @turf/area@3.14.0
│ │ │ ├── @mapbox/geojson-area@0.2.2 deduped
│ │ │ └── @turf/meta@3.14.0
│ │ ├─┬ @turf/bbox@3.14.0
│ │ │ └── @turf/meta@3.14.0 deduped
│ │ ├─┬ @turf/explode@3.14.0
│ │ │ ├── @turf/helpers@3.13.0 deduped
│ │ │ └── @turf/meta@3.14.0 deduped
│ │ ├── @turf/helpers@3.13.0
│ │ ├─┬ @turf/inside@3.14.0
│ │ │ └── @turf/invariant@3.13.0 deduped
│ │ ├── @turf/invariant@3.13.0
│ │ ├─┬ grid-to-matrix@1.4.0
│ │ │ ├── @turf/helpers@5.1.5
│ │ │ ├─┬ @turf/invariant@5.2.0
│ │ │ │ └── @turf/helpers@5.1.5 deduped
│ │ │ └─┬ @turf/meta@5.2.0
│ │ │   └── @turf/helpers@5.1.5 deduped
│ │ └── marchingsquares@1.2.3
│ ├─┬ @turf/isolines@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├─┬ grid-to-matrix@1.2.0
│ │ │ ├── @turf/helpers@4.7.3 deduped
│ │ │ ├── @turf/invariant@4.7.3 deduped
│ │ │ └── @turf/meta@4.7.4 deduped
│ │ └── marchingsquares@1.2.0
│ ├─┬ @turf/kinks@4.7.3
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/line-arc@4.7.3
│ │ ├── @turf/circle@4.7.3 deduped
│ │ ├── @turf/destination@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/line-chunk@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/line-distance@4.7.3 deduped
│ │ ├── @turf/line-slice-along@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/line-distance@4.7.3
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/line-intersect@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-segment@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └─┬ geojson-rbush@1.2.0
│ │   ├── @turf/meta@4.7.4 deduped
│ │   └── rbush@2.0.2 deduped
│ ├─┬ @turf/line-offset@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/line-overlap@4.7.3
│ │ ├── @turf/boolean-point-on-line@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-segment@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/point-on-line@4.7.3 deduped
│ │ ├── deep-equal@1.0.1
│ │ └── geojson-rbush@1.2.0 deduped
│ ├─┬ @turf/line-segment@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/line-slice@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/point-on-line@4.7.3 deduped
│ ├─┬ @turf/line-slice-along@4.7.3
│ │ ├── @turf/bearing@4.7.3 deduped
│ │ ├── @turf/destination@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/line-split@4.7.3
│ │ ├── @turf/flatten@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-intersect@4.7.3 deduped
│ │ ├── @turf/line-segment@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/point-on-line@4.7.3 deduped
│ │ ├── @turf/truncate@4.7.3 deduped
│ │ └── geojson-rbush@1.2.0 deduped
│ ├─┬ @turf/linestring-to-polygon@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/mask@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/union@4.7.3 deduped
│ │ └── rbush@2.0.2 deduped
│ ├── @turf/meta@4.7.4
│ ├─┬ @turf/midpoint@4.7.3
│ │ ├── @turf/bearing@4.7.3 deduped
│ │ ├── @turf/destination@4.7.3 deduped
│ │ └── @turf/distance@4.7.3 deduped
│ ├─┬ @turf/nearest@4.7.3
│ │ └── @turf/distance@4.7.3 deduped
│ ├─┬ @turf/planepoint@4.7.3
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/point-grid@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/inside@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/point-on-line@4.7.3
│ │ ├── @turf/bearing@4.7.3 deduped
│ │ ├── @turf/destination@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-intersect@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/point-on-surface@4.7.3
│ │ ├── @turf/center@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/explode@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/inside@4.7.3 deduped
│ ├─┬ @turf/point-to-line-distance@4.7.3
│ │ ├── @turf/bearing@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/rhumb-bearing@4.7.3 deduped
│ │ └── @turf/rhumb-distance@4.7.3 deduped
│ ├─┬ @turf/polygon-tangents@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/polygon-to-linestring@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── @turf/invariant@4.7.3 deduped
│ ├─┬ @turf/polygonize@4.7.3
│ │ └─┬ polygonize@1.0.1
│ │   ├── @turf/envelope@4.7.3 deduped
│ │   ├── @turf/helpers@4.7.3 deduped
│ │   ├── @turf/inside@4.7.3 deduped
│ │   ├── @turf/invariant@4.7.3 deduped
│ │   └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/random@4.7.3
│ │ └── geojson-random@0.2.2
│ ├─┬ @turf/rewind@4.7.3
│ │ ├── @turf/boolean-clockwise@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/rhumb-bearing@4.7.3
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── geodesy@1.1.2
│ ├─┬ @turf/rhumb-destination@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── geodesy@1.1.2 deduped
│ ├─┬ @turf/rhumb-distance@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ └── geodesy@1.1.2 deduped
│ ├─┬ @turf/sample@4.7.3
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/sector@4.7.3
│ │ ├── @turf/circle@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/line-arc@4.7.3 deduped
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/simplify@4.7.3
│ │ ├── @turf/clean-coords@4.7.3 deduped
│ │ ├── @turf/clone@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── simplify-js@1.2.3
│ ├─┬ @turf/square@4.7.3
│ │ └── @turf/distance@4.7.3 deduped
│ ├─┬ @turf/square-grid@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/distance@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/tag@4.7.3
│ │ └── @turf/inside@4.7.3 deduped
│ ├─┬ @turf/tesselate@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ └── earcut@2.1.3
│ ├─┬ @turf/tin@4.7.3
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/transform-rotate@4.7.3
│ │ ├── @turf/centroid@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/rhumb-bearing@4.7.3 deduped
│ │ ├── @turf/rhumb-destination@4.7.3 deduped
│ │ └── @turf/rhumb-distance@4.7.3 deduped
│ ├─┬ @turf/transform-scale@4.7.3
│ │ ├── @turf/bbox@4.7.3 deduped
│ │ ├── @turf/center@4.7.3 deduped
│ │ ├── @turf/centroid@4.7.3 deduped
│ │ ├── @turf/clone@4.7.3 deduped
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ ├── @turf/rhumb-bearing@4.7.3 deduped
│ │ ├── @turf/rhumb-destination@4.7.3 deduped
│ │ └── @turf/rhumb-distance@4.7.3 deduped
│ ├─┬ @turf/transform-translate@4.7.3
│ │ ├── @turf/invariant@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └── @turf/rhumb-destination@4.7.3 deduped
│ ├─┬ @turf/triangle-grid@4.7.3
│ │ ├── @turf/distance@4.7.3 deduped
│ │ └── @turf/helpers@4.7.3 deduped
│ ├─┬ @turf/truncate@4.7.3
│ │ └── @turf/meta@4.7.4 deduped
│ ├─┬ @turf/union@4.7.3
│ │ └── jsts@1.3.0 deduped
│ ├─┬ @turf/unkink-polygon@4.7.3
│ │ ├── @turf/helpers@4.7.3 deduped
│ │ ├── @turf/meta@4.7.4 deduped
│ │ └─┬ simplepolygon@1.2.1
│ │   ├─┬ @turf/area@3.14.0
│ │   │ ├── @mapbox/geojson-area@0.2.2 deduped
│ │   │ └── @turf/meta@3.14.0
│ │   ├── @turf/helpers@3.13.0
│ │   ├── @turf/inside@4.7.3 deduped
│ │   ├─┬ @turf/within@3.14.0
│ │   │ ├── @turf/helpers@3.13.0 deduped
│ │   │ └─┬ @turf/inside@3.14.0
│ │   │   └── @turf/invariant@3.13.0
│ │   ├─┬ debug@2.6.9
│ │   │ └── ms@2.0.0
│ │   ├─┬ geojson-polygon-self-intersections@1.2.0
│ │   │ └── rbush@2.0.2 deduped
│ │   └── rbush@2.0.2 deduped
│ └─┬ @turf/within@4.7.3
│   ├── @turf/helpers@4.7.3 deduped
│   └── @turf/inside@4.7.3 deduped
├─┬ aws-sdk@2.259.1
│ ├─┬ buffer@4.9.1
│ │ ├── base64-js@1.3.0
│ │ ├── ieee754@1.1.8 deduped
│ │ └── isarray@1.0.0
│ ├── events@1.1.1
│ ├── ieee754@1.1.8
│ ├── jmespath@0.15.0
│ ├── querystring@0.2.0
│ ├── sax@1.2.1
│ ├─┬ url@0.10.3
│ │ ├── punycode@1.3.2
│ │ └── querystring@0.2.0 deduped
│ ├── uuid@3.1.0
│ └─┬ xml2js@0.4.17
│   ├── sax@1.2.1 deduped
│   └─┬ xmlbuilder@4.2.1
│     └── lodash@4.17.10 deduped
├─┬ cross-env@5.2.0
│ ├─┬ cross-spawn@6.0.5
│ │ ├── nice-try@1.0.4
│ │ ├── path-key@2.0.1
│ │ ├── semver@5.5.0
│ │ ├─┬ shebang-command@1.2.0
│ │ │ └── shebang-regex@1.0.0
│ │ └─┬ which@1.3.1
│ │   └── isexe@2.0.0
│ └── is-windows@1.0.2
├─┬ csvtojson@1.1.12
│ ├── lodash@4.17.10
│ └─┬ strip-bom@2.0.0
│   └── is-utf8@0.2.1
├── limiter@1.1.3
├── logdown@2.2.0
├── ngeohash@0.6.0
├─┬ node-geocoder@3.22.0
│ ├── bluebird@3.5.1
│ ├─┬ request@2.87.0
│ │ ├── aws-sign2@0.7.0
│ │ ├── aws4@1.7.0
│ │ ├── caseless@0.12.0
│ │ ├─┬ combined-stream@1.0.6
│ │ │ └── delayed-stream@1.0.0
│ │ ├── extend@3.0.1
│ │ ├── forever-agent@0.6.1
│ │ ├─┬ form-data@2.3.2
│ │ │ ├── asynckit@0.4.0
│ │ │ ├── combined-stream@1.0.6 deduped
│ │ │ └── mime-types@2.1.18 deduped
│ │ ├─┬ har-validator@5.0.3
│ │ │ ├─┬ ajv@5.5.2
│ │ │ │ ├── co@4.6.0
│ │ │ │ ├── fast-deep-equal@1.1.0
│ │ │ │ ├── fast-json-stable-stringify@2.0.0
│ │ │ │ └── json-schema-traverse@0.3.1
│ │ │ └── har-schema@2.0.0
│ │ ├─┬ http-signature@1.2.0
│ │ │ ├── assert-plus@1.0.0
│ │ │ ├─┬ jsprim@1.4.1
│ │ │ │ ├── assert-plus@1.0.0 deduped
│ │ │ │ ├── extsprintf@1.3.0
│ │ │ │ ├── json-schema@0.2.3
│ │ │ │ └─┬ verror@1.10.0
│ │ │ │   ├── assert-plus@1.0.0 deduped
│ │ │ │   ├── core-util-is@1.0.2 deduped
│ │ │ │   └── extsprintf@1.3.0 deduped
│ │ │ └─┬ sshpk@1.14.2
│ │ │   ├── asn1@0.2.3 deduped
│ │ │   ├── assert-plus@1.0.0 deduped
│ │ │   ├─┬ bcrypt-pbkdf@1.0.1
│ │ │   │ └── tweetnacl@0.14.5 deduped
│ │ │   ├─┬ dashdash@1.14.1
│ │ │   │ └── assert-plus@1.0.0 deduped
│ │ │   ├─┬ ecc-jsbn@0.1.1
│ │ │   │ └── jsbn@0.1.1 deduped
│ │ │   ├─┬ getpass@0.1.7
│ │ │   │ └── assert-plus@1.0.0 deduped
│ │ │   ├── jsbn@0.1.1
│ │ │   ├── safer-buffer@2.1.2
│ │ │   └── tweetnacl@0.14.5
│ │ ├── is-typedarray@1.0.0
│ │ ├── isstream@0.1.2
│ │ ├── json-stringify-safe@5.0.1
│ │ ├─┬ mime-types@2.1.18
│ │ │ └── mime-db@1.33.0
│ │ ├── oauth-sign@0.8.2
│ │ ├── performance-now@2.1.0
│ │ ├── qs@6.5.2
│ │ ├── safe-buffer@5.1.2
│ │ ├─┬ tough-cookie@2.3.4
│ │ │ └── punycode@1.4.1
│ │ ├─┬ tunnel-agent@0.6.0
│ │ │ └── safe-buffer@5.1.2 deduped
│ │ └── uuid@3.2.1 deduped
│ └─┬ request-promise@4.2.2
│   ├── bluebird@3.5.1 deduped
│   ├─┬ request-promise-core@1.1.1
│   │ └── lodash@4.17.10 deduped
│   ├── stealthy-require@1.1.1
│   └── tough-cookie@2.3.4 deduped
├── q@1.5.1
├─┬ redis@2.8.0
│ ├── double-ended-queue@2.1.0-0
│ ├── redis-commands@1.3.5
│ └── redis-parser@2.6.0
├─┬ serverless-aws-documentation@1.1.0
│ └── object-hash@1.3.0
├─┬ serverless-graph@0.3.2
│ ├── bluebird@3.5.1 deduped
│ └─┬ cloudformation-graph@1.1.3
│   ├── bluebird@3.5.1 deduped
│   ├── is-valid-json@1.0.2
│   ├── lodash@4.17.10 deduped
│   └─┬ yamljs@0.2.10
│     ├─┬ argparse@1.0.10
│     │ └── sprintf-js@1.0.3
│     └── glob@7.1.2 deduped
├─┬ serverless-offline@3.25.4
│ ├─┬ babel-register@6.26.0
│ │ ├─┬ babel-core@6.26.3
│ │ │ ├─┬ babel-code-frame@6.26.0
│ │ │ │ ├─┬ chalk@1.1.3
│ │ │ │ │ ├── ansi-styles@2.2.1
│ │ │ │ │ ├── escape-string-regexp@1.0.5
│ │ │ │ │ ├─┬ has-ansi@2.0.0
│ │ │ │ │ │ └── ansi-regex@2.1.1
│ │ │ │ │ ├─┬ strip-ansi@3.0.1
│ │ │ │ │ │ └── ansi-regex@2.1.1 deduped
│ │ │ │ │ └── supports-color@2.0.0
│ │ │ │ ├── esutils@2.0.2
│ │ │ │ └── js-tokens@3.0.2
│ │ │ ├─┬ babel-generator@6.26.1
│ │ │ │ ├── babel-messages@6.23.0 deduped
│ │ │ │ ├── babel-runtime@6.26.0 deduped
│ │ │ │ ├── babel-types@6.26.0 deduped
│ │ │ │ ├─┬ detect-indent@4.0.0
│ │ │ │ │ └─┬ repeating@2.0.1
│ │ │ │ │   └─┬ is-finite@1.0.2
│ │ │ │ │     └── number-is-nan@1.0.1
│ │ │ │ ├── jsesc@1.3.0
│ │ │ │ ├── lodash@4.17.10 deduped
│ │ │ │ ├── source-map@0.5.7 deduped
│ │ │ │ └── trim-right@1.0.1
│ │ │ ├─┬ babel-helpers@6.24.1
│ │ │ │ ├── babel-runtime@6.26.0 deduped
│ │ │ │ └── babel-template@6.26.0 deduped
│ │ │ ├─┬ babel-messages@6.23.0
│ │ │ │ └── babel-runtime@6.26.0 deduped
│ │ │ ├── babel-register@6.26.0 deduped
│ │ │ ├── babel-runtime@6.26.0 deduped
│ │ │ ├─┬ babel-template@6.26.0
│ │ │ │ ├── babel-runtime@6.26.0 deduped
│ │ │ │ ├── babel-traverse@6.26.0 deduped
│ │ │ │ ├── babel-types@6.26.0 deduped
│ │ │ │ ├── babylon@6.18.0 deduped
│ │ │ │ └── lodash@4.17.10 deduped
│ │ │ ├─┬ babel-traverse@6.26.0
│ │ │ │ ├── babel-code-frame@6.26.0 deduped
│ │ │ │ ├── babel-messages@6.23.0 deduped
│ │ │ │ ├── babel-runtime@6.26.0 deduped
│ │ │ │ ├── babel-types@6.26.0 deduped
│ │ │ │ ├── babylon@6.18.0 deduped
│ │ │ │ ├── debug@2.6.9 deduped
│ │ │ │ ├── globals@9.18.0
│ │ │ │ ├─┬ invariant@2.2.4
│ │ │ │ │ └─┬ loose-envify@1.3.1
│ │ │ │ │   └── js-tokens@3.0.2 deduped
│ │ │ │ └── lodash@4.17.10 deduped
│ │ │ ├─┬ babel-types@6.26.0
│ │ │ │ ├── babel-runtime@6.26.0 deduped
│ │ │ │ ├── esutils@2.0.2 deduped
│ │ │ │ ├── lodash@4.17.10 deduped
│ │ │ │ └── to-fast-properties@1.0.3
│ │ │ ├── babylon@6.18.0
│ │ │ ├── convert-source-map@1.5.1
│ │ │ ├── debug@2.6.9 deduped
│ │ │ ├── json5@0.5.1
│ │ │ ├── lodash@4.17.10 deduped
│ │ │ ├─┬ minimatch@3.0.4
│ │ │ │ └─┬ brace-expansion@1.1.11
│ │ │ │   ├── balanced-match@1.0.0
│ │ │ │   └── concat-map@0.0.1
│ │ │ ├── path-is-absolute@1.0.1
│ │ │ ├── private@0.1.8
│ │ │ ├── slash@1.0.0
│ │ │ └── source-map@0.5.7
│ │ ├─┬ babel-runtime@6.26.0
│ │ │ ├── core-js@2.5.7 deduped
│ │ │ └── regenerator-runtime@0.11.1
│ │ ├── core-js@2.5.7
│ │ ├─┬ home-or-tmp@2.0.0
│ │ │ ├── os-homedir@1.0.2
│ │ │ └── os-tmpdir@1.0.2
│ │ ├── lodash@4.17.10 deduped
│ │ ├─┬ mkdirp@0.5.1
│ │ │ └── minimist@0.0.8
│ │ └─┬ source-map-support@0.4.18
│ │   └── source-map@0.5.7 deduped
│ ├─┬ boom@4.3.1
│ │ └── hoek@4.2.1
│ ├─┬ h2o2@5.4.0
│ │ ├─┬ boom@3.2.2
│ │ │ └── hoek@4.2.1 deduped
│ │ ├── hoek@4.2.1 deduped
│ │ ├─┬ joi@9.2.0
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ ├── isemail@2.2.1
│ │ │ ├── items@2.1.1 deduped
│ │ │ ├── moment@2.22.2
│ │ │ └── topo@2.0.2 deduped
│ │ └─┬ wreck@9.0.0
│ │   ├─┬ boom@3.2.2
│ │   │ └── hoek@4.2.1 deduped
│ │   └── hoek@4.2.1 deduped
│ ├─┬ hapi@14.2.0
│ │ ├─┬ accept@2.1.4
│ │ │ ├─┬ boom@5.2.0
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ └── hoek@4.2.1 deduped
│ │ ├─┬ ammo@2.0.4
│ │ │ ├─┬ boom@5.2.0
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ └── hoek@4.2.1 deduped
│ │ ├─┬ boom@3.2.2
│ │ │ └── hoek@4.2.1 deduped
│ │ ├─┬ call@3.0.4
│ │ │ ├── boom@4.3.1 deduped
│ │ │ └── hoek@4.2.1 deduped
│ │ ├─┬ catbox@7.1.5
│ │ │ ├─┬ boom@5.2.0
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ └─┬ joi@10.6.0
│ │ │   ├── hoek@4.2.1 deduped
│ │ │   ├── isemail@2.2.1 deduped
│ │ │   ├── items@2.1.1 deduped
│ │ │   └── topo@2.0.2 deduped
│ │ ├─┬ catbox-memory@2.0.4
│ │ │ └── hoek@4.2.1 deduped
│ │ ├─┬ cryptiles@3.1.2
│ │ │ └─┬ boom@5.2.0
│ │ │   └── hoek@4.2.1 deduped
│ │ ├─┬ heavy@4.0.4
│ │ │ ├─┬ boom@5.2.0
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ └─┬ joi@10.6.0
│ │ │   ├── hoek@4.2.1 deduped
│ │ │   ├── isemail@2.2.1 deduped
│ │ │   ├── items@2.1.1 deduped
│ │ │   └── topo@2.0.2 deduped
│ │ ├── hoek@4.2.1 deduped
│ │ ├─┬ iron@4.0.5
│ │ │ ├─┬ boom@5.2.0
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ ├── cryptiles@3.1.2 deduped
│ │ │ └── hoek@4.2.1 deduped
│ │ ├── items@2.1.1
│ │ ├── joi@9.2.0 deduped
│ │ ├─┬ kilt@2.0.2
│ │ │ └── hoek@4.2.1 deduped
│ │ ├─┬ mimos@3.0.3
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ └── mime-db@1.33.0 deduped
│ │ ├── peekaboo@2.0.2
│ │ ├─┬ shot@3.4.2
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ └─┬ joi@10.6.0
│ │ │   ├── hoek@4.2.1 deduped
│ │ │   ├── isemail@2.2.1 deduped
│ │ │   ├── items@2.1.1 deduped
│ │ │   └── topo@2.0.2 deduped
│ │ ├─┬ statehood@4.1.0
│ │ │ ├─┬ boom@3.2.2
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ ├── cryptiles@3.1.2 deduped
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ ├── iron@4.0.5 deduped
│ │ │ ├── items@2.1.1 deduped
│ │ │ └── joi@9.2.0 deduped
│ │ ├─┬ subtext@4.4.1
│ │ │ ├─┬ boom@5.2.0
│ │ │ │ └── hoek@4.2.1 deduped
│ │ │ ├─┬ content@3.0.7
│ │ │ │ └─┬ boom@5.2.0
│ │ │ │   └── hoek@4.2.1 deduped
│ │ │ ├── hoek@4.2.1 deduped
│ │ │ ├─┬ pez@2.1.5
│ │ │ │ ├── b64@3.0.3
│ │ │ │ ├─┬ boom@5.2.0
│ │ │ │ │ └── hoek@4.2.1 deduped
│ │ │ │ ├── content@3.0.7 deduped
│ │ │ │ ├── hoek@4.2.1 deduped
│ │ │ │ └─┬ nigel@2.0.2
│ │ │ │   ├── hoek@4.2.1 deduped
│ │ │ │   └─┬ vise@2.0.2
│ │ │ │     └── hoek@4.2.1 deduped
│ │ │ └─┬ wreck@12.5.1
│ │ │   ├── boom@5.2.0 deduped
│ │ │   └── hoek@4.2.1 deduped
│ │ └─┬ topo@2.0.2
│ │   └── hoek@4.2.1 deduped
│ ├── hapi-cors-headers@1.0.3
│ ├── js-string-escape@1.0.1
│ ├── jsonpath-plus@0.16.0
│ ├─┬ jsonwebtoken@8.3.0
│ │ ├─┬ jws@3.1.5
│ │ │ ├─┬ jwa@1.1.6
│ │ │ │ ├── buffer-equal-constant-time@1.0.1
│ │ │ │ ├─┬ ecdsa-sig-formatter@1.0.10
│ │ │ │ │ └── safe-buffer@5.1.2 deduped
│ │ │ │ └── safe-buffer@5.1.2 deduped
│ │ │ └── safe-buffer@5.1.2 deduped
│ │ ├── lodash.includes@4.3.0
│ │ ├── lodash.isboolean@3.0.3
│ │ ├── lodash.isinteger@4.0.4
│ │ ├── lodash.isnumber@3.0.3
│ │ ├── lodash.isplainobject@4.0.6
│ │ ├── lodash.isstring@4.0.1
│ │ ├── lodash.once@4.1.1
│ │ └── ms@2.1.1
│ ├── lodash@4.17.10 deduped
│ ├── uuid@3.2.1 deduped
│ └── velocityjs@0.9.6
├─┬ serverless-plugin-warmup@3.3.0-rc.1
│ ├── bluebird@3.5.1 deduped
│ └─┬ fs-extra@3.0.1
│   ├── graceful-fs@4.1.11
│   ├─┬ jsonfile@3.0.1
│   │ └── graceful-fs@4.1.11 deduped
│   └── universalify@0.1.1
├── serverless-pseudo-parameters@1.6.0
├─┬ serverless-python-requirements@4.1.0
│ ├── bluebird@3.5.1 deduped
│ ├─┬ fs-extra@6.0.1
│ │ ├── graceful-fs@4.1.11 deduped
│ │ ├─┬ jsonfile@4.0.0
│ │ │ └── graceful-fs@4.1.11 deduped
│ │ └── universalify@0.1.1 deduped
│ ├─┬ glob-all@3.1.0
│ │ ├─┬ glob@7.1.2
│ │ │ ├── fs.realpath@1.0.0
│ │ │ ├─┬ inflight@1.0.6
│ │ │ │ ├── once@1.4.0 deduped
│ │ │ │ └── wrappy@1.0.2
│ │ │ ├── inherits@2.0.3
│ │ │ ├── minimatch@3.0.4 deduped
│ │ │ ├─┬ once@1.4.0
│ │ │ │ └── wrappy@1.0.2 deduped
│ │ │ └── path-is-absolute@1.0.1 deduped
│ │ └─┬ yargs@1.2.6
│ │   └── minimist@0.1.0
│ ├── is-wsl@1.1.0
│ ├─┬ jszip@3.1.5
│ │ ├── core-js@2.3.0
│ │ ├── es6-promise@3.0.2
│ │ ├─┬ lie@3.1.1
│ │ │ └── immediate@3.0.6
│ │ ├── pako@1.0.6
│ │ └─┬ readable-stream@2.0.6
│ │   ├── core-util-is@1.0.2
│ │   ├── inherits@2.0.3 deduped
│ │   ├── isarray@1.0.0 deduped
│ │   ├── process-nextick-args@1.0.7
│ │   ├── string_decoder@0.10.31
│ │   └── util-deprecate@1.0.2
│ ├── lodash.get@4.4.2
│ ├── lodash.set@4.3.2
│ ├── lodash.uniqby@4.7.0
│ ├── lodash.values@4.3.0
│ └─┬ rimraf@2.6.2
│   └── glob@7.1.2 deduped
├─┬ ssh2-sftp-client@2.2.1
│ └─┬ ssh2@0.5.5
│   └─┬ ssh2-streams@0.1.20
│     ├── asn1@0.2.3
│     ├── semver@5.5.0 deduped
│     └── streamsearch@0.1.2
├─┬ supercluster@3.0.1
│ └── kdbush@1.0.1
└── uuid@3.2.1

dschep pushed a commit that referenced this issue Sep 8, 2018
Fixes #157 (filed by me)

## What this does
* Makes the download caching of pip a "first-class citizen" as an option directly in this plugin's options.  This will "fix" a few (attempts) at using the pip cache, specifically in Docker, and will simplify this feature (as the user simply has to enable it, not specify a folder).  In a future MR, I'd highly suggest enabling this by default.
* Second, it adds a new type of caching called "static caching" which allows you to cache the outputs of this plugin.  This greatly speeds up every single build as long as you have the feature enabled and do not change your requirements.txt file.  In a future MR, I'd highly suggest enabling this by default also.
* The pip download and static cache are shared between any projects of the same user through an [appdir](https://www.npmjs.com/package/appdirectory) cache folder when packaging your service.  This _especially_ helps on projects that heavily use Docker (Win/Mac) for deployments or development, or for pip modules that need to compile every time, and _especially_ for projects with long requirements.txt files.  This will also greatly help the longer and more complex your requirements.txt is, and/or if you use the same requirements.txt on multiple projects (common in team environments).

## Implementation details
* When either cache is enabled, this plugin now caches those requirements (download or static) to an "appdir" cache folder (per the [appdirectory](https://www.npmjs.com/package/appdirectory) node module).
* When this feature is NOT enabled, nothing changes
* Injection happens directly from the new cached requirements directory via a symlink created in the right place in `.serverless` or `.serverless/functionname` if deploying individually.
* As mentioned above, there is a symlink into the .serverless folder when the static cache is enabled pointing to it, so you still "know" where your cache is (for both individually and non-individually packaged functions).
* The requirements.txt "generator" was improved to remove comments, empty lines, and sort the list of items before trying to use it (or check its md5 sum).  This allows for more actual md5 matches between projects, in-case of comments and such in the requirements file.
* A new command was added to the command-line to flush the download/static cache, called cleanCache invokable with: `serverless requirements cleanCache`.  This clears all items including the download and static cache.
* A handful of new tests were created for various edge conditions I've found while doing this refactoring, some were based on bugs other people found while using this plugin with some combination of options, some are not directly related to this merge's intent, but it's just part of my stream of work/consciousness.  Sorry tests take a lot longer to run now since there are lots more now.
* A UID bug fix related to docker + pip was implemented (seen on a few other bugs) from @cgrimal 
* The following new configurable custom options were added to this plugin...

Variable Name | Value | Description
--- | --- | ---
useStaticCache | `false/true` | Default: false.  This will enable or disable the static cache.  After  some testing I would like to make this default: true, as this will greatly help everyone, and there's no reason to not enable this.  Possibly making this default: true will help weed out issues faster.  I'll gladly step-up to quickly fix any bugs people have with it since I'm now well accustomed with the code.
useDownloadCache | `false/true` | Default: false.  This will enable or disable the pip download cache.  This was previously the "example" code using a pipEnvExtraCmd to specify a local folder to cache downloads to.  This does not require a cache location to be set, if not specified it will use an appdirs.usercache() location.
cacheLocation | `<path>` | Default: [appdirectory](https://www.npmjs.com/package/appdirectory).userCache(appName: serverless-python-requirements) This will allow the user to specify where the caches (both static and download) should be stored.  This will be useful for people who want to do advanced things like storing cache globally shared between users, or for CI/CD build servers on shared-storage to allow multiple build machines to leverage a cache to speed builds up.  An example would be to mount a shared NFS store on all your CI/CD runners to `/mnt/shared` and set this value to `/mnt/shared/sls-py-cache`. 
staticCacheMaxVersions | `<integer>` | Default: 0.  This will restrict the a maximum number of caches in the cache folder.  Setting to 0 makes no maximum number of versions.  This will be useful for build/CI/CD machines that have limited disk space and don't want to (potentially) infinitely cache hundreds/thousands of versions of items in cache. Although, I would be disturbed if a project had hundreds of changes to their requirements.txt file.

## TODO
- [X] Feature Implementation
- [X] BUG: Deploying single-functions fails (Packaging works, but fails because of #161 )
- [X] Code Styling / Linting
- [X] Test to be sure Pipfile / generated requirements.txt still works
- [X] Tested a bunch on Mac / Linux with and without Docker
- [X] Adding Tests for Download Cache
- [X] Make sure zip feature still works
- [X] Ensure all existing tests pass
- [X] Adding Tests for static cache
- [X] Updating README.md to inform users how to use it
- [X] Make sure dockerSsh works
- [X] Implement error when trying to use --cache-dir with dockerizePip (won't work)
- [X] Implement suggestion when trying to use --cache-dir without dockerizePip
- [x] Test on Windows
- [x] Iterate through any feedback
- [x] Rebase with master constantly, awaiting merge...  :)

Replaces #162
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants