Repository: azukaar/GuPM
Branch: master
Commit: 53371f326bf9
Files: 52
Total size: 92.8 KB
Directory structure:
gitextract_o4jwiwqj/
├── .circleci/
│ └── config.yml
├── .gitignore
├── .gupm_rc.gs
├── LICENCE
├── build.gs
├── ci/
│ └── publish.gs
├── docs/
│ └── install.sh
├── gupm.json
├── plugins/
│ ├── provider-git/
│ │ ├── gupm.json
│ │ ├── postGetDependency.gs
│ │ └── resolveDependencyLocation.gs
│ ├── provider-http/
│ │ ├── gupm.json
│ │ └── resolveDependencyLocation.gs
│ └── provider-https/
│ ├── gupm.json
│ └── resolveDependencyLocation.gs
├── readme.md
├── src/
│ ├── addDependency.go
│ ├── bootstrap.go
│ ├── cache.go
│ ├── cli.go
│ ├── cli_test.go
│ ├── defaultProvider/
│ │ ├── defaultProvider.go
│ │ └── publish.go
│ ├── distribution_gupm.json
│ ├── gitHooks.go
│ ├── global.go
│ ├── index.go
│ ├── installProject.go
│ ├── jsVm/
│ │ └── jsVm.go
│ ├── plugins.go
│ ├── provider/
│ │ ├── bootstrap.go
│ │ ├── dependencyTree.go
│ │ ├── install.go
│ │ ├── provider.go
│ │ └── publish.go
│ ├── publish.go
│ ├── removeDependency.go
│ ├── self.go
│ ├── test.go
│ ├── ui/
│ │ └── log.go
│ ├── utils/
│ │ ├── files.go
│ │ ├── json.go
│ │ ├── repo.go
│ │ ├── types.go
│ │ ├── untar.go
│ │ └── utils.go
│ └── windows/
│ └── windows_install.go
└── tests/
├── install/
│ └── normal.test.gs
├── make/
│ ├── nodeps.test.gs
│ └── normal.test.gs
├── plugins/
│ └── normal.test.gs
└── scripts/
└── normal.test.gs
================================================
FILE CONTENTS
================================================
================================================
FILE: .circleci/config.yml
================================================
version: 2
jobs:
build:
docker:
- image: golang:1.12.5-stretch
steps:
- checkout
- run:
name: Install GuPM
command: curl -fsSL https://azukaar.github.io/GuPM/install.sh | bash
- run:
name: Install provider
command: g plugin install https://azukaar.github.io/GuPM-official/repo:provider-go
- run:
name: Make
command: g make
- run:
name: Build
command: g build
- run:
name: Cleanup
command: g pl delete provider-go
- run:
name: Run tests
command: g test
- run:
name: Run unit tests
command: g gotest
- run:
name: Install provider
command: g plugin install https://azukaar.github.io/GuPM-official/repo:provider-go
- run:
name: Build Linux
command: g ci/publish
- run:
name: Build Mac
command: g ci/publish mac
- run:
name: Build Windows
command: g ci/publish windows
- run: git config user.email "nobody@circleci.com"
- run: git config user.name "Circle Ci"
- run: git add docs
- run: git commit -m "[skip ci] Release"
- run: git push origin master
workflows:
version: 2
build-all:
jobs:
- build:
filters:
branches:
only:
- master
================================================
FILE: .gitignore
================================================
.DS_Store
.bin
build
.vscode
node_modules
temp
cache
sampleproject
test.gs
package.json
go_modules
gupm_modules
================================================
FILE: .gupm_rc.gs
================================================
env("GOPATH", run("go", ["env", "GOROOT"]) + ":" + pwd() + "/go_modules")
================================================
FILE: LICENCE
================================================
Copyright (c) Yann Stepienik (yann.stepienik@gmail.com)
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
================================================
FILE: build.gs
================================================
removeFiles(["build/dg", "build/plugins", "build/gupm.json"])
var goArgs = ["build", "-o", "build/dg"]
goArgs = goArgs.concat(dir("src/*.go"))
exec("go", goArgs)
copyFiles("plugins", "build/plugins")
copyFiles("src/distribution_gupm.json", "build/gupm.json")
console.log("\nBuild done! 💖")
================================================
FILE: ci/publish.gs
================================================
removeFiles("gupm")
var goArgs = ["build", "-o"]
if(typeof $1 != "undefined" && $1 == "windows") {
goArgs.push("gupm/g.exe")
} else {
goArgs.push("gupm/g")
}
goArgs = goArgs.concat(dir("src/*.go"))
copyFiles("plugins", "gupm/plugins")
copyFiles("src/distribution_gupm.json", "gupm/gupm.json")
if(typeof $1 != "undefined" && $1 == "mac") {
env("GOOS", "darwin")
env("go version", "amd64")
exec("go", goArgs)
var arch = tar("gupm")
removeFiles("docs/gupm_mac.tar.gz")
saveFileAt(arch, "docs/gupm_mac.tar.gz")
}
if(typeof $1 != "undefined" && $1 == "windows") {
env("GOOS", "windows")
env("GOARCH", "amd64")
exec("go", goArgs)
var arch = tar("gupm")
removeFiles("docs/gupm_windows.tar.gz")
saveFileAt(arch, "docs/gupm_windows.tar.gz")
} else {
env("GOOS", "linux")
env("GOARCH", "amd64")
exec("go", goArgs)
var arch = tar("gupm")
removeFiles("docs/gupm.tar.gz")
saveFileAt(arch, "docs/gupm.tar.gz")
}
removeFiles("gupm")
================================================
FILE: docs/install.sh
================================================
#!/bin/sh
if [ "$(uname)" = "Darwin" ]; then
curl --output gupm.tar.gz https://azukaar.github.io/GuPM/gupm_mac.tar.gz
elif [ "$(uname)" = "Linux" ]; then
curl --output gupm.tar.gz https://azukaar.github.io/GuPM/gupm.tar.gz
fi
mkdir ~/.gupm
tar -C ~/.gupm -zxvf gupm.tar.gz
chmod -R 755 ~/.gupm/gupm/
rm gupm.tar.gz
if [ -d "/usr/local/bin" ]
then
if [ -f "/usr/local/bin/g" ]
then
rm /usr/local/bin/g
fi
ln -s ~/.gupm/gupm/g /usr/local/bin/g
else
if [ -f "/bin/g" ]
then
rm /bin/g
fi
ln -s ~/.gupm/gupm/g /bin/g
fi
if [ "$(uname)" = "Darwin" ]; then
read -r -p "Do you want to make Homebrew your default provider? (Recommended) [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]
then
g plugin install https://azukaar.github.io/GuPM-official/repo:provider-brew
sed -ie 's/"defaultProvider": "gupm"/"defaultProvider": "os"/' ~/.gupm/gupm/gupm.json
fi
fi
echo "------"
echo "Installaton complete"
echo "------"
================================================
FILE: gupm.json
================================================
{
"cli": {
"aliases": {
"gotest": "go test ./src ./src/utils",
"start": "./build/dg"
}
},
"dependencies": {
"default": {
"go://github.com/Masterminds/semver": "master",
"go://github.com/bmatcuk/doublestar": "master",
"go://github.com/fatih/color": "master",
"go://github.com/gosuri/uilive": "master",
"go://github.com/mattn/go-isatty": "master",
"go://github.com/mitchellh/go-homedir": "master",
"go://github.com/otiai10/copy": "master",
"go://github.com/robertkrimen/otto": "master",
"go://github.com/stretchr/testify": "master",
"go://gopkg.in/sourcemap.v1": "v1.0.5"
},
"defaultProvider": "go"
},
"git": {
"hooks": {
"precommit": "gofmt -w -s src/index.go $StagedFiles(**/*.go)",
"prepush": [
"g test",
"g gotest"
]
}
},
"name": "gupm",
"version": "1.2.1"
}
================================================
FILE: plugins/provider-git/gupm.json
================================================
{
"name": "provider-git",
"version": "0.0.1",
"config": {
"default": {
"entrypoint": "gupm.json",
"installPath": "gupm_modules"
}
}
}
================================================
FILE: plugins/provider-git/postGetDependency.gs
================================================
// Provider : name of provider (npm)
// Name : name of downloaded package
// Version : version of downloaded package
// Url : URL of downloaded package
// Path : Future path of downloaded package
// Result : binary downloaded
var folder = unzip(Result);
var firstChildrenName = Object.keys(folder.Children)[0];
var firstChildren = folder.Children[firstChildrenName];
saveFileAt(firstChildren, Path);
saveLockDep(Path);
Path;
================================================
FILE: plugins/provider-git/resolveDependencyLocation.gs
================================================
var name = Dependency.name;
var version = Dependency.version;
Dependency.url = 'https://' + name + '/archive/master.zip'
if(Dependency.version === "*.*.*") {
Dependency.version = "master"
}
// https://github.com/src-d/go-git/archive/6e931e4fdefa202c76242109453447182ae16444.zip
Dependency;
================================================
FILE: plugins/provider-http/gupm.json
================================================
{
"name": "provider-http",
"version": "0.0.1",
"config": {
"default": {
"entrypoint": "gupm.json",
"installPath": "gupm_modules"
}
}
}
================================================
FILE: plugins/provider-http/resolveDependencyLocation.gs
================================================
var name = Dependency.name;
if(name.split(':').length > 1) {
var version = Dependency.version
var names = name.split(':')
// exact version
if (version.match(/^\d+\.\d+\.\d+/) && !version.match(/\sx/)) {
}
// test ranges
else {
var repoList = 'http://' + names[0] + '/gupm_repo.json'
var payload = httpGetJson(repoList);
if(payload.packages[names[1]] && payload.packages[names[1]].length) {
var versionList = payload.packages[names[1]];
version = semverLatestInRange(version, versionList);
} else {
console.error("Package "+names[1]+" not found in " + names[0])
exit(1)
}
}
var realName = names[1]
var namespace = ''
if( realName.split('/').length > 1) {
namespace = (realName.split('/')[0] + '/').replace("OS", _OSNAME)
realName = realName.split('/')[1]
}
Dependency.url = 'http://' + names[0] + '/' + namespace + realName + '/' + version + '/' + realName + '-' + version + '.tgz'
Dependency.version = version
} else {
Dependency.url = 'http://' + name
}
Dependency;
================================================
FILE: plugins/provider-https/gupm.json
================================================
{
"name": "provider-https",
"version": "0.0.1",
"config": {
"default": {
"entrypoint": "gupm.json",
"installPath": "gupm_modules"
}
}
}
================================================
FILE: plugins/provider-https/resolveDependencyLocation.gs
================================================
var name = Dependency.name;
if(name.split(':').length > 1) {
var version = Dependency.version
var names = name.split(':')
// exact version
if (version.match(/^\d+\.\d+\.\d+/) && !version.match(/\sx/)) {
}
// test ranges
else {
var repoList = 'https://' + names[0] + '/gupm_repo.json'
var payload = httpGetJson(repoList);
if(payload.packages[names[1]] && payload.packages[names[1]].length) {
var versionList = payload.packages[names[1]];
version = semverLatestInRange(version, versionList);
} else {
console.error("Package "+names[1]+" not found in " + names[0])
exit(1)
}
}
var realName = names[1]
var namespace = ''
if( realName.split('/').length > 1) {
namespace = (realName.split('/')[0] + '/').replace("OS", _OSNAME)
realName = realName.split('/')[1]
}
Dependency.url = 'https://' + names[0] + '/' + namespace + realName + '/' + version + '/' + realName + '-' + version + '.tgz'
Dependency.version = version
} else {
Dependency.url = 'https://' + name
}
Dependency;
================================================
FILE: readme.md
================================================

---
Global Universal Project Manager -- Package manager, CLI tool, and scripts for all your projects and your system. Whether you are a developer managing dependencies, or a sysadmin looking for your new toolbelt (bye bash!) you are among friends. Check the Wiki for documentation.
* ⏱ **Fast**. Written in native code, with real multi-threading.
* 👓 **Smart**. Memory efficient solution using hard-link, which do not duplicate dependencies across project.
* 🌍 **Global**. Windows, Mac and Linux compatibility.
* 🌈 **Universal**. Usable in any kind of project (Ruby, JS, Go, C, Python, etc...)
* 👗 **Customizable**. Flexible plugin system: make GuPM your own.
* 👝 **Future Proof**. Let's make this the last PM you will ever need.
* 🌳 **Decentralized**. You keep control of the sources you tap into.
* 🐳 **No dependencies**. You don't need anythind else (you don't need NPM to use NPM's repository with GuPM)
This idea is born from the frustration of having to give up my habits whenever I would switch off Javascript and lose NPM (Whether it would be in Ruby, Go, or even situations outside of coding). GuPM is claiming to take inspiration from the best things in Brew, NPM, Gem, etc... And compile them in a single tool, usable in any project.
* 📦 **Packages Manager**. Install packages from any repository and manage dependencies in a seamless way.
* 🖥 **CLI Manager**. Install and use CLI tools in a flexible way without conflicts.
* 🚏 **Scripting**. GuPM is bundled with GuScript, allowing you to build cross platform scripts for your project.
* 🐙 **Packed with features**. Manage configs, git hooks, parallel executions, environment variables, CI, and more.
* 🔥 **Even more to come!** See : [Next](https://github.com/azukaar/GuPM/projects/1#column-5571474) for the roadmap of feature. You are welcomed to contribute!
---
# Getting started :
## Quick links
* [Wiki](https://github.com/azukaar/GuPM/wiki)
* [Quick Start](https://github.com/azukaar/GuPM/wiki/quick-start)
* [Getting started with Node](https://medium.com/@azukaar/gupm-to-manage-your-node-js-project-b7664503f3de?sk=f901b86d888b44dcdb78c644bd5df002)
* [Getting started with Go](https://medium.com/@azukaar/gupm-to-manage-your-go-project-5d19c341403c)
* [Create your own repository](https://github.com/azukaar/GuPM/wiki/repositories)
* [Official GuPM repository](https://github.com/azukaar/GuPM-official)
## Installation
### Linux and Mac OS :
⌨️ `$ curl -fsSL https://azukaar.github.io/GuPM/install.sh | bash`
### Windows
💾 [Windows_install.exe](https://azukaar.github.io/GuPM/windows_install.exe)
## JS/NPM example
This example is setting up a project using the [NPM plugin](https://github.com/azukaar/GuPM-official).
More details on how to use GuPM with node [here]().
## Go example
This example is setting up a project using the [Go plugin](https://github.com/azukaar/GuPM-official).
More details on how to use GuPM with Go [here]().
# Dependency Manager
## New projects
In order to simply bootstrap a new project you can run `g bootstrap` you can also use `b` and add a provider `g b -p npm`
## Make
This command will set up your project by getting dependencies. Adding a -p or --provider argument allows you to specify what provider to use initially.
Please note you do NOT need to install npm / gem / whatever to use their corresponding provider, GuPM implement everything itself.
```bash
# reads gupm.json
g make
# reads package.json
g make -p npm
```
## Install
```bash
# use default repo [Config in gupm.json]
g install mysql
g i mysql
# use brew
g install brew://mysql
g install -p brew mysql
# use NPM
g install npm://react@1 # will save in gupm.json
g install -p npm react@1 # will save in package.json
```
More commands [in the wiki](https://github.com/azukaar/GuPM/wiki/cli-references)
## GuPM management
### Plugins
GuPM needs plugins to work with various repos :
```bash
# Install provider-go from the official repo
g plugin install https://azukaar.github.io/GuPM-official/repo:provider-go
```
See https://github.com/azukaar/gupm-official for a list of officially suported plugins.
See https://github.com/azukaar/GuPM/wiki/how-to-create-a-provider to create your own.
### updates
GuPM can be managed using :
```bash
g self upgrade
```
More commands [in the wiki](https://github.com/azukaar/GuPM/wiki/cli-references)
## Write GuPM scripts
You can use GuScript to write bash-like files, used for setting up your project, use it, or anything literally.
Think of GuScript as a replacement for your bash scripts.
```
// name_setup.gs
var name = input('What is your name')
echo('Welcome' + name)
saveName(name)
```
GuScript is based on javascript, and therefore allow advanced object/arrays manipulations, function definitions, etc...
Find more details about the available APIs in the [wiki](https://github.com/azukaar/GuPM/wiki) 1
## VS Code
Add this to your `settings.json` to treat .gs file as javascript (temporary fix to plain text)
```
"files.associations": {
"*.gs": "javascript"
}
```
# Thanks!
Package Icon made by [smashicons](https://www.smashicons.com/)
Dog Icon made by [Freepik](https://www.freepik.com/)
================================================
FILE: src/addDependency.go
================================================
package main
import (
"./provider"
"./ui"
"./utils"
)
func AddDependency(path string, rls []string) error {
var err error
var packageConfig utils.Json
var depList []map[string]interface{}
var depProvider = Provider
ui.Title("Add dependency...")
if !ProviderWasForced && utils.FileExists(path+utils.Path("/gupm.json")) {
config, _ := utils.ReadGupmJson(path + utils.Path("/gupm.json"))
if config.Dependencies.DefaultProvider != "" {
depProvider = config.Dependencies.DefaultProvider
}
}
err = provider.InitProvider(Provider)
if err != nil {
return err
}
providerConfig, err = provider.GetProviderConfig(Provider)
if err != nil {
return err
}
packageConfig, err = provider.GetPackageConfig(path)
if err != nil {
return err
}
packageConfig, err = provider.PostGetPackageConfig(packageConfig)
if err != nil {
return err
}
depList, err = provider.GetDependencyList(packageConfig)
if err != nil {
return err
}
ui.Title("Adding to dependency list...")
for _, str := range rls {
dep := utils.BuildDependencyFromString(depProvider, str)
resolved, err := provider.ResolveDependencyLocation(dep)
if err != nil || resolved["url"].(string) == "" {
ui.Error("Can't resolve", str)
return err
}
dep["version"] = resolved["version"]
depList = append(depList, dep)
}
if packageConfig != nil {
err = provider.SaveDependencyList(path, depList)
if err != nil {
return err
}
}
return nil
}
================================================
FILE: src/bootstrap.go
================================================
package main
import (
"./provider"
"./ui"
// "fmt"
)
func Bootstrap(path string) error {
err := provider.InitProvider(Provider)
if err != nil {
return err
}
ui.Title("Bootstrap project")
errBoot := provider.Bootstrap(path)
if errBoot != nil {
return errBoot
} else {
ui.Title("Bootstrap done! ❤️")
}
return nil
}
================================================
FILE: src/cache.go
================================================
package main
import (
"./ui"
"./utils"
"github.com/mitchellh/go-homedir"
)
func CacheClear() {
hdir, errH := homedir.Dir()
if errH != nil {
ui.Error(errH)
hdir = "."
}
folder := utils.Path(hdir + "/.gupm/cache/")
utils.RemoveFiles([]string{folder})
}
================================================
FILE: src/cli.go
================================================
package main
import (
"fmt"
"regexp"
"strconv"
"strings"
"./ui"
"./utils"
)
type json = utils.Json
var ProviderWasForced = false
type Arguments map[string]string
func (a *Arguments) AsJson() json {
res := utils.Json{}
for i, v := range *a {
res[i] = v
}
return res
}
func (a *Arguments) Join() string {
res := ""
for i, v := range *a {
if v == "true" || v == "false" {
res += "--" + strings.ToLower(i) + " "
} else if ok, _ := regexp.MatchString(`^\$\d+`, i); ok {
res += v + " "
} else {
res += "--" + strings.ToLower(i) + " " + v + " "
}
}
return strings.TrimSpace(res)
}
func (a *Arguments) AsList() []string {
res := []string{}
i := 1
for (*a)["$"+strconv.Itoa(i)] != "" {
res = append(res, (*a)["$"+strconv.Itoa(i)])
i++
}
return res
}
func (a *Arguments) Shift() {
i := 2
for (*a)["$"+strconv.Itoa(i)] != "" {
(*a)["$"+strconv.Itoa(i-1)] = (*a)["$"+strconv.Itoa(i)]
i++
}
(*a)["$"+strconv.Itoa(i-1)] = ""
}
func GetArgs(args []string) (string, Arguments) {
arguments := make(Arguments)
next := ""
dolsI := 1
if len(args) == 0 {
arguments["$0"] = ""
return "", arguments
}
command := args[0]
if len(args) < 2 {
arguments["$0"] = command
return command, arguments
}
argsToParse := args[1:]
for _, value := range argsToParse {
nameCheck := regexp.MustCompile(`^--?(\w+)`)
tryname := nameCheck.FindString(value)
if tryname != "" {
long, _ := regexp.MatchString(`^--`, tryname)
if long {
tryname = tryname[1:]
}
if next != "" {
arguments[next] = "true"
next = ""
}
next = strings.ToUpper(tryname[1:2]) + tryname[2:]
} else {
if next != "" {
arguments[next] = value
next = ""
} else {
arguments["$"+strconv.FormatInt(int64(dolsI), 10)] = value
dolsI++
}
}
}
if next != "" {
arguments[next] = "true"
}
arguments["$0"] = command + " " + arguments.Join()
return command, arguments
}
func getProvider(c string, args Arguments) string {
gupmConfig := utils.GupmConfig()
defaultProvider := "gupm"
if c == "install" || c == "global" {
defaultProvider = gupmConfig.DefaultProvider
}
if defaultProvider == "os" {
osName := utils.OSNAME()
if gupmConfig.OsProviders[osName] != "" {
defaultProvider = gupmConfig.OsProviders[osName]
} else {
ui.Error("No provider set for", osName)
return utils.DIRNAME()
}
}
if utils.FileExists("gupm.json") {
config, err := utils.ReadGupmJson("gupm.json")
if err != nil {
ui.Error(err)
} else {
if config.Cli.DefaultProviders[c] != "" {
defaultProvider = config.Cli.DefaultProviders[c]
}
}
}
if args["Provider"] != "" {
ProviderWasForced = true
return args["Provider"]
} else if args["P"] != "" {
ProviderWasForced = true
return args["P"]
} else {
return defaultProvider
}
}
func ExecCli(c string, args Arguments) (bool, error) {
var err error
notFound := "Cannot find commmand"
shorthands := map[string]string{
"h": "help",
"m": "make",
"i": "install",
"d": "delete",
"p": "publish",
"b": "bootstrap",
"c": "cache",
"s": "self",
"t": "test",
"pl": "plugin",
"g": "global",
}
if shorthands[c] != "" {
c = shorthands[c]
}
if provider := getProvider(c, args); provider != "" {
Provider = provider
}
if c == "help" {
fmt.Println("make / m :", "[--provider=]", "Install projects depdencies based on info in the entry point (depends on provider)")
fmt.Println("install / i :", "[--provider=]", "Install package")
fmt.Println("remove / r :", "[--provider=]", "remove package from module config")
fmt.Println("publish / p :", "[--provider=]", "publish a project based on the model of your specific provider")
fmt.Println("bootstrap / b :", "[--provider=]", "bootstrap a new project based on the model of your specific provider")
fmt.Println("test / t :", "[--provider=] Run project's tests in tests folder.")
fmt.Println("global / g :", "install or delete global packages")
fmt.Println("cache / c :", "clear or check the cache with \"cache clear\" or \"cache check\"")
fmt.Println("self / s :", "self manage gupm. Try g \"self upgrade\" or \"g self uninstall\"")
fmt.Println("plugin / pl :", "To install a plugin \"g pl install\". Then use \"g pl create\" to create a new one and \"g pl link\" to test your plugin")
} else if c == "make" {
BuildGitHooks(".")
err = InstallProject(".")
} else if c == "install" {
err = AddDependency(".", args.AsList())
if err == nil {
err = InstallProject(".")
}
} else if c == "publish" {
err = Publish(".", args["$1"])
} else if c == "delete" {
err = RemoveDependency(".", args.AsList())
} else if c == "global" {
if args["$1"] == "install" || args["$1"] == "i" {
args.Shift()
GlobalAdd(args.AsList())
} else if args["$1"] == "delete" || args["$1"] == "d" {
args.Shift()
GlobalDelete(args.AsList())
} else {
ui.Error(notFound, args["$1"], "\n", "try install or delete")
}
} else if c == "plugin" {
if args["$1"] == "create" {
PluginCreate(".")
} else if args["$1"] == "link" {
PluginLink(".")
} else if args["$1"] == "install" {
err = PluginInstall(".", args.AsList()[1:])
} else if args["$1"] == "delete" {
PluginDelete(".", args.AsList()[1:])
} else {
ui.Error(notFound, args["$1"], "\n", "try cache clear or cache check")
}
} else if c == "cache" {
if args["$1"] == "clear" {
CacheClear()
} else if args["$1"] == "check" {
ui.Error("Not implemented yet.")
} else {
ui.Error(notFound, args["$1"], "\n", "try cache clear or cache check")
}
} else if c == "self" {
if args["$1"] == "upgrade" {
SelfUpgrade()
} else if args["$1"] == "uninstall" {
SelfUninstall()
} else {
ui.Error(notFound, args["$1"])
}
} else if c == "bootstrap" {
err = Bootstrap(".")
} else if c == "test" {
RunTest("tests")
} else if c == "hook" {
RunHook(".", args["$1"])
} else {
return false, nil
}
return true, err
}
================================================
FILE: src/cli_test.go
================================================
package main
import (
"testing"
// "reflect"
_ "fmt"
"github.com/stretchr/testify/require"
)
func TestArgs(t *testing.T) {
require := require.New(t)
// Basic
command, args := GetArgs([]string{"make", "-p", "npm"})
require.Equal("make", command)
require.Equal(Arguments{"$0": "make --p npm", "P": "npm"}, args)
// Nothing
command, args = GetArgs([]string{})
require.Equal("", command)
require.Equal(Arguments{"$0": ""}, args)
// No args
command, args = GetArgs([]string{"install"})
require.Equal("install", command)
require.Equal(Arguments{"$0": "install"}, args)
// bools and long mix
command, args = GetArgs([]string{"install", "--dev", "--provider", "npm"})
require.Equal("install", command)
require.Equal(Arguments{"$0": "install --dev --provider npm", "Dev": "true", "Provider": "npm"}, args)
command, args = GetArgs([]string{"install", "--provider", "npm", "--dev"})
require.Equal("install", command)
require.Equal(Arguments{"$0": "install --provider npm --dev", "Dev": "true", "Provider": "npm"}, args)
// bools at the end
command, args = GetArgs([]string{"install", "--dev"})
require.Equal("install", command)
require.Equal(Arguments{"$0": "install --dev", "Dev": "true"}, args)
// long args
command, args = GetArgs([]string{"install", "--provider", "npm"})
require.Equal("install", command)
require.Equal(Arguments{"$0": "install --provider npm", "Provider": "npm"}, args)
// anonymous
command, args = GetArgs([]string{"install", "npm"})
require.Equal("install", command)
require.Equal(Arguments{"$0": "install npm", "$1": "npm"}, args)
// asList
command, args = GetArgs([]string{"install", "go", "npm"})
require.Equal([]string{"go", "npm"}, args.AsList())
}
================================================
FILE: src/defaultProvider/defaultProvider.go
================================================
package defaultProvider
import (
"encoding/json"
"io/ioutil"
"os"
"reflect"
"regexp"
"../ui"
"../utils"
)
func Bootstrap(path string) {
if utils.FileExists(utils.Path(path + "/gupm.json")) {
ui.Error("A project already exists in this folder. Aborting bootstrap.")
return
}
name := ui.WaitForInput("Please enter the name of the project: ")
description := ui.WaitForInput("Enter a description: ")
author := ui.WaitForInput("Enter the author: ")
licence := ui.WaitForInput("Enter the licence (ISC): ")
if name == "" {
ui.Error("Name cannot be empty. Try again")
return
} else {
if licence == "" {
licence = "ISC"
}
fileContent := `{
"name": "` + name + `",
"version": "0.0.1",
"description": "` + description + `",
"author": "` + author + `",
"licence": "` + licence + `"
}`
ioutil.WriteFile(utils.Path(path+"/gupm.json"), []byte(fileContent), os.ModePerm)
}
}
func GetPackageConfig(entryPoint string) map[string]interface{} {
var packageConfig map[string]interface{}
b, err := ioutil.ReadFile(entryPoint)
if err != nil {
ui.Error(err.Error() + " : " + entryPoint)
}
json.Unmarshal([]byte(string(b)), &packageConfig)
return packageConfig
}
func GetDependency(provider string, name string, version string, url string, path string) (string, error) {
return string(utils.HttpGet(url)), nil
}
func PostGetDependency(provider string, name string, version string, url string, path string, result string) (string, error) {
os.MkdirAll(path, os.ModePerm)
tarCheck := regexp.MustCompile(`\.tgz$`)
tryTar := tarCheck.FindString(url)
gzCheck := regexp.MustCompile(`\.gz$`)
trygz := gzCheck.FindString(url)
zipCheck := regexp.MustCompile(`\.zip$`)
tryZip := zipCheck.FindString(url)
if tryTar != "" {
resultFiles, err := utils.Untar(result)
if err != nil {
return path, err
}
resultFiles.SaveAt(path)
} else if trygz != "" {
resultFiles, err := utils.Ungz(result)
if err != nil {
return path, err
}
resultFiles.SaveAt(path)
} else if tryZip != "" {
resultFiles, err := utils.Unzip(result)
if err != nil {
return path, err
}
resultFiles.SaveAt(path)
}
utils.SaveLockDep(path)
return path, nil
}
func GetDependencyList(config map[string]interface{}) []map[string]interface{} {
if config == nil {
ui.Error("no config found. Please bootstrap the project with `g bootstrap`")
return nil
}
depEnv, ok := config["dependencies"].(map[string]interface{})
if !ok {
ui.Log("no dependencies")
return nil
}
depList, hasDefault := depEnv["default"].(map[string]interface{})
if !hasDefault {
ui.Log("no dependencies")
return nil
}
result := make([]map[string]interface{}, 0)
for name, value := range depList {
dep := utils.BuildDependencyFromString("gupm", name)
if reflect.TypeOf(value).String() == "string" {
dep["version"] = value
} else {
valueObject := value.(map[string]interface{})
if valueObject["provider"].(string) != "" {
dep["provider"] = valueObject["provider"]
}
if valueObject["version"].(string) != "" {
dep["version"] = valueObject["version"]
}
}
result = append(result, dep)
}
return result
}
func ExpandDependency(dependency map[string]interface{}) (map[string]interface{}, error) {
configFilePath := utils.Path(dependency["path"].(string) + "/gupm.json")
if utils.FileExists(configFilePath) {
config := GetPackageConfig(configFilePath)
dependency["dependencies"] = make(map[string]interface{})
if config["dependencies"] != nil {
dependency["dependencies"] = GetDependencyList(config)
}
}
return dependency, nil
}
func BinaryInstall(dest string, packagePath string) error {
packages, _ := utils.ReadDir(packagePath)
for _, dep := range packages {
configFilePath := utils.Path(packagePath + "/" + dep.Name() + "/gupm.json")
if utils.FileExists(configFilePath) {
config := GetPackageConfig(configFilePath)
if config["binaries"] != nil {
bins := config["binaries"].(map[string]string)
for name, relPath := range bins {
os.Symlink(utils.Path("/../gupm_modules/"+"/"+dep.Name()+relPath), utils.Path(dest+"/"+name))
}
}
}
}
return nil
}
func SaveDependencyList(path string, depList []map[string]interface{}) error {
config := GetPackageConfig(utils.Path(path + "/gupm.json"))
if config["dependencies"] == nil {
config["dependencies"] = make(map[string]interface{})
}
config["dependencies"].(map[string]interface{})["default"] = make(map[string]interface{})
for _, dep := range depList {
key := utils.BuildStringFromDependency(map[string]interface{}{
"provider": dep["provider"].(string),
"name": dep["name"].(string),
})
config["dependencies"].(map[string]interface{})["default"].(map[string]interface{})[key] = dep["version"].(string)
}
utils.WriteJsonFile(utils.Path(path+"/"+"gupm.json"), config)
return nil
}
================================================
FILE: src/defaultProvider/publish.go
================================================
package defaultProvider
import (
"os"
"../ui"
"../utils"
)
func Publish(path string, namespace string) error {
configPath := utils.Path(path + "/gupm.json")
if utils.FileExists(configPath) {
packageConfig := new(utils.GupmEntryPoint)
errConfig := utils.ReadJSON(configPath, &packageConfig)
if errConfig != nil {
ui.Error("Can't read provider configuration")
return errConfig
}
pname := packageConfig.Name
if namespace != "" {
pname = namespace + "/" + pname
}
ppath := utils.Path(path + "/" + packageConfig.Publish.Dest)
repoConfig := utils.GetOrCreateRepo(ppath)
packageList := repoConfig["packages"].(map[string]interface{})
if packageList[pname] != nil {
if utils.Contains(packageList[pname], packageConfig.Version) {
ui.Error("Package " + pname + "@" + packageConfig.Version + " already published. Please bump the version number.")
return nil
} else {
packageList[pname] = append(utils.ArrString(packageList[pname]), packageConfig.Version)
}
} else {
packageList[pname] = make([]string, 0)
packageList[pname] = append(utils.ArrString(packageList[pname]), packageConfig.Version)
}
installPath := ppath + utils.Path("/"+pname+"/"+packageConfig.Version)
os.MkdirAll(installPath, os.ModePerm)
sourcePaths := make([]string, 0)
for _, src := range packageConfig.Publish.Source {
sourcePaths = append(sourcePaths, utils.Path(path+"/"+src))
}
arch, _ := utils.Tar(sourcePaths)
arch.SaveAt(installPath + utils.Path("/"+packageConfig.Name+"-"+packageConfig.Version+".tgz"))
repoConfig["packages"] = packageList
utils.SaveRepo(ppath, repoConfig)
} else {
ui.Error("Can't find provider configuration")
}
return nil
}
================================================
FILE: src/distribution_gupm.json
================================================
{
"name": "gupm",
"config": {
"default": {
"entrypoint": "gupm.json",
"installPath": "gupm_modules",
"defaultProvider": "gupm",
"osProviders": {
"linux": "linux",
"mac": "brew",
"windows": "chocolatey"
}
}
}
}
================================================
FILE: src/gitHooks.go
================================================
package main
import (
"fmt"
"os"
"regexp"
"strings"
"./utils"
"github.com/bmatcuk/doublestar"
)
func BuildGitHooks(path string) {
if utils.FileExists(".git") {
if !utils.FileExists(".git/hooks/pre-commit") {
utils.WriteFile(".git/hooks/pre-commit", "g hook precommit")
}
if !utils.FileExists(".git/hooks/pre-push") {
utils.WriteFile(".git/hooks/pre-push", "g hook prepush")
}
}
}
func runhook(hook string) {
commandList := strings.Split(hook, " ")
stagedFiles, _ := utils.RunCommand("git", []string{"diff", "--cached", "--name-only"})
unPushedFiles := ""
fyg, _ := utils.RunCommand("git", []string{"log", "--branches", "--not", "--remotes", "--name-status", "--oneline"})
unPushedFilesRaw := strings.Split(fyg, "\n")
extractFileName := regexp.MustCompile(`^[AM]\b(.*)`)
for _, v := range unPushedFilesRaw {
if extracted := extractFileName.FindStringSubmatch(v); len(extracted) > 0 {
unPushedFiles += strings.Trim(extracted[1], " ") + "\n"
}
}
unPushedFiles = strings.Trim(unPushedFiles, " ")
for i, v := range commandList {
stagedFilesCheck := regexp.MustCompile(`^\$StagedFiles(\(([\w\/\.\*\-\_]+)?\)?)?`)
tryStagedFiles := stagedFilesCheck.FindStringSubmatch(v)
unpushedFilesCheck := regexp.MustCompile(`^\$UnpushedFiles(\(([\w\/\.\*\-\_]+)?\)?)?`)
tryUnpushedFiles := unpushedFilesCheck.FindStringSubmatch(v)
if len(tryStagedFiles) == 3 {
if tryStagedFiles[2] == "" {
commandList[i] = strings.ReplaceAll(stagedFiles, " ", "\\ ")
commandList[i] = strings.ReplaceAll(commandList[i], "\n", " ")
} else {
commandList[i] = ""
stagedFilesList := strings.Split(stagedFiles, "\n")
for _, s := range stagedFilesList {
isIn, _ := doublestar.Match(tryStagedFiles[2], s)
if isIn {
commandList[i] += strings.ReplaceAll(s, " ", "\\ ") + " "
}
}
commandList[i] = strings.Trim(commandList[i], " ")
}
}
if len(tryUnpushedFiles) == 3 {
if tryUnpushedFiles[2] == "" {
commandList[i] = strings.ReplaceAll(unPushedFiles, " ", "\\ ")
commandList[i] = strings.ReplaceAll(commandList[i], "\n", " ")
} else {
commandList[i] = ""
unpushedFilesList := strings.Split(unPushedFiles, "\n")
for _, s := range unpushedFilesList {
isIn, _ := doublestar.Match(tryUnpushedFiles[2], s)
if isIn {
commandList[i] += strings.ReplaceAll(s, " ", "\\ ") + " "
}
}
commandList[i] = strings.Trim(commandList[i], " ")
}
}
}
commandListConsolidated := strings.Trim(strings.Join(commandList, " "), " ")
commandList = strings.Split(commandListConsolidated, " ")
err := utils.ExecCommand(commandList[0], append(commandList[1:]))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func runhooklist(hooklist string) {
hooks := strings.Split(hooklist, ";")
for _, hook := range hooks {
runhook(strings.Trim(hook, " "))
}
}
func runHooks(hooks interface{}) {
ch := make(chan int)
listHooks, isArray := hooks.([]interface{})
if isArray {
for _, hook := range listHooks {
go func(hook string) {
runhooklist(hook)
ch <- 0
}(hook.(string))
}
for range listHooks {
<-ch
}
} else {
runhooklist(hooks.(string))
}
}
func RunHook(path string, hook string) {
config, _ := utils.ReadGupmJson("gupm.json")
if hook == "precommit" && config.Git.Hooks.Precommit != nil {
runHooks(config.Git.Hooks.Precommit)
}
if hook == "prepush" && config.Git.Hooks.Prepush != nil {
runHooks(config.Git.Hooks.Prepush)
}
}
================================================
FILE: src/global.go
================================================
package main
import (
"os"
"path/filepath"
"./ui"
"./utils"
)
func installBins(path string) {
var GLOBAL = utils.Path(utils.HOMEDIR(".") + "/.gupm/global")
bins := utils.RecursiveFileWalkDir(GLOBAL + "/.bin")
for _, bin := range bins {
name := filepath.Base(bin)
if !utils.FileExists(path + "/" + name) {
os.Symlink(bin, path+"/"+name)
}
}
}
func GlobalAdd(rls []string) {
ui.Title("Installing global dependency...")
var GLOBAL = utils.Path(utils.HOMEDIR(".") + "/.gupm/global")
if !utils.FileExists(GLOBAL + utils.Path("/gupm.json")) {
os.MkdirAll(GLOBAL, os.ModePerm)
utils.WriteFile(GLOBAL+utils.Path("/gupm.json"), "{}")
}
ui.Log("Installing...")
AddDependency(GLOBAL, rls)
InstallProject(GLOBAL)
ui.Log("Add binaries...")
if utils.OSNAME() != "windows" {
if utils.FileExists("/usr/local/bin/") {
installBins("/usr/local/bin/")
} else {
installBins("/usr/bin/")
}
} else {
ui.Error("Global Installation not supported on Windows yet. Please add .gupm/global/.bin to your PATH")
}
}
func GlobalDelete(rls []string) {
var GLOBAL = utils.Path(utils.HOMEDIR(".") + "/.gupm/global")
if !utils.FileExists(GLOBAL + utils.Path("/gupm.json")) {
os.MkdirAll(GLOBAL, os.ModePerm)
utils.WriteFile(GLOBAL+utils.Path("/gupm.json"), "{}")
}
RemoveDependency(GLOBAL, rls)
}
================================================
FILE: src/index.go
================================================
package main
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"./jsVm"
"./ui"
"./utils"
)
var Provider string
func ScriptExists(path string) string {
if utils.FileExists(path + ".gs") {
return path + ".gs"
} else if utils.FileExists(path) && !utils.IsDirectory(path) {
return path
} else {
return ""
}
}
func executeFile(path string, args Arguments) {
_, err := jsVm.Run(path, args.AsJson())
if err != nil {
ui.Error("File execution failed")
ui.Error(err)
Exit(1)
}
}
func binFile(name string, args []string) {
path := utils.Path("./.bin/" + name)
realPath, _ := filepath.EvalSymlinks(path)
err := utils.ExecCommand(realPath, args)
if err != nil {
ui.Error(err)
Exit(1)
}
}
func Exit(code int) {
ui.Stop()
os.Exit(code)
}
func runAlias(alias string) {
commands := strings.Split(alias, ";")
for _, command := range commands {
commandList := strings.Split(command, " ")
err := utils.ExecCommand(commandList[0], append(commandList[1:], os.Args[2:]...))
if err != nil {
ui.Error(err)
}
}
}
func runAliasList(aliasList string) {
aliases := strings.Split(aliasList, ";")
for _, alias := range aliases {
runhook(strings.Trim(alias, " "))
}
}
func main() {
binFolder := make(map[string]bool)
if utils.FileExists(".bin") {
files, _ := utils.ReadDir(".bin")
for _, file := range files {
binFolder[file.Name()] = true
}
}
c, args := GetArgs(os.Args[1:])
if utils.FileExists(".gupm_rc.gs") {
executeFile(".gupm_rc.gs", args)
}
aliases := map[string]interface{}{}
if utils.FileExists("gupm.json") {
packageConfig, errConfig := utils.ReadGupmJson("gupm.json")
if errConfig != nil {
ui.Error(errConfig)
} else {
aliases = packageConfig.Cli.Aliases
}
}
script := ScriptExists(c)
if didExec, err := ExecCli(c, args); didExec {
if err != nil {
ui.Error(err)
Exit(1)
}
if script != "" {
executeFile(script, args)
}
} else if c == "env" || c == "e" {
toProcess := os.Args[2:]
re := regexp.MustCompile(`([\w\-\_]+)=([\w\-\_]+)`)
isEnv := re.FindAllStringSubmatch(toProcess[0], -1)
for isEnv != nil {
name := isEnv[0][1]
value := isEnv[0][2]
os.Setenv(name, value)
toProcess = toProcess[1:]
isEnv = re.FindAllStringSubmatch(toProcess[0], -1)
}
utils.ExecCommand(toProcess[0], toProcess[1:])
} else if aliases[c] != nil {
ch := make(chan int)
listAlias, isArray := aliases[c].([]interface{})
if isArray {
for _, aliasLine := range listAlias {
go func(aliasLine string) {
runAliasList(aliasLine)
ch <- 0
}(aliasLine.(string))
}
for range listAlias {
<-ch
}
} else {
runAliasList(aliases[c].(string))
}
} else if binFolder[c] == true {
binFile(c, os.Args[2:])
} else if script != "" {
executeFile(script, args)
} else if c == "" {
fmt.Println("Welcome to GuPM version 1.0.0 \ntry 'g help' for a list of commands. Try 'g filename' to execute a file.")
} else {
fmt.Println("Command not found. Try 'g help' or check filename.")
Exit(1)
}
ui.Stop()
}
================================================
FILE: src/installProject.go
================================================
package main
import (
"errors"
"fmt"
"sync"
"time"
"./provider"
"./ui"
"./utils"
"github.com/mitchellh/go-homedir"
)
var cacheExpanded = make(map[string]map[string]interface{})
var lock = sync.RWMutex{}
var lockList = sync.RWMutex{}
func expandDepList(depList []map[string]interface{}) []map[string]interface{} {
channel := make(chan int)
for index, dep := range depList {
go (func(channel chan int, index int, dep map[string]interface{}) {
if dep["expanded"] != true {
newDep := make(map[string]interface{})
for key, value := range dep {
newDep[key] = value
}
newDep, errExpand := provider.ResolveDependencyLocation(newDep)
if newDep == nil {
ui.Error("Provider " + dep["provider"].(string) + " didnt resolve " + dep["name"].(string) + "@" + dep["version"].(string))
ui.Error(errExpand)
channel <- 0
return
}
hdir, errH := homedir.Dir()
if errH != nil {
ui.Error(errH)
hdir = "."
}
_, ok := newDep["url"].(string)
if !ok || newDep["url"].(string) == "" {
ui.Error("Cannot resolve : " + newDep["name"].(string))
channel <- 1
return
}
newDep["path"] = hdir + "/.gupm/cache/" + newDep["provider"].(string) + "/" + newDep["name"].(string) + "/" + newDep["version"].(string)
if !utils.FileExists(newDep["path"].(string)) || !utils.FileExists(newDep["path"].(string)+"/.gupm_locked") {
getRes, errorGD := provider.GetDependency(
newDep["provider"].(string),
newDep["name"].(string),
newDep["version"].(string),
newDep["url"].(string),
newDep["path"].(string),
)
if errorGD != nil {
ui.Error(errorGD)
}
newPath, errorPGD := provider.PostGetDependency(
newDep["provider"].(string),
newDep["name"].(string),
newDep["version"].(string),
newDep["url"].(string),
newDep["path"].(string),
getRes,
)
newDep["path"] = newPath
if errorPGD != nil {
ui.Error(errorPGD)
}
}
lock.Lock()
if newDep["expanded"] != true {
if cacheExpanded[newDep["url"].(string)]["expanded"] != true {
newDep, errExpand = provider.ExpandDependency(newDep)
if errExpand != nil || newDep == nil || len(newDep) == 0 {
ui.Error("Provider " + dep["provider"].(string) + " didnt expand " + dep["name"].(string) + "@" + dep["version"].(string))
ui.Error(errExpand)
channel <- 0
return
}
newDep["expanded"] = true
cacheExpanded[newDep["url"].(string)] = newDep
} else {
newDep = cacheExpanded[newDep["url"].(string)]
}
}
ui.Log("Get dependency " + newDep["name"].(string))
lock.Unlock()
lockList.Lock()
depList[index] = newDep
nextDepList, ok := depList[index]["dependencies"].([]map[string]interface{})
lockList.Unlock()
if ok {
res := expandDepList(nextDepList)
lockList.Lock()
depList[index]["dependencies"] = res
lockList.Unlock()
}
}
channel <- 1
})(channel, index, dep)
}
for range depList {
i := <-channel
if i == 0 {
return nil
}
}
return depList
}
func installDep(path string, depList []map[string]interface{}) map[string]string {
installPaths := make(map[string]string)
installPathsLock := sync.RWMutex{}
var channel = make(chan int)
for index, dep := range depList {
go (func(channel chan int, index int, dep map[string]interface{}) {
depProviderConfig, err := provider.GetProviderConfig(dep["provider"].(string))
destination := utils.Path(path + "/" + depProviderConfig.Config.Default.InstallPath)
if dep["path"] != nil {
packageConfig, errC := utils.ReadGupmJson(utils.Path(dep["path"].(string) + "/gupm.json"))
if errC == nil && packageConfig != nil && packageConfig.WrapInstallFolder != "" {
destination += utils.Path("/" + packageConfig.WrapInstallFolder)
}
}
ui.Error(err)
ui.Log("Installing " + path)
provider.InstallDependency(destination, dep)
// if path == "." {
installPathsLock.Lock()
installPaths[dep["provider"].(string)] = utils.Path(path + "/" + depProviderConfig.Config.Default.InstallPath)
installPathsLock.Unlock()
// }
nextDepList, ok := depList[index]["dependencies"].([]map[string]interface{})
if ok {
installDep(utils.Path(destination+"/"+depList[index]["name"].(string)), nextDepList)
}
channel <- 1
})(channel, index, dep)
}
for range depList {
<-channel
}
return installPaths
}
var providerConfig *utils.GupmEntryPoint
func InstallProject(path string) error {
start := time.Now()
ui.Title("Installing project...")
var err error
var packageConfig utils.Json
var depList []map[string]interface{}
err = provider.InitProvider(Provider)
if err != nil {
return err
}
providerConfig, err = provider.GetProviderConfig(Provider)
ui.Error(err)
packageConfig, _ = provider.GetPackageConfig(path)
packageConfig, _ = provider.PostGetPackageConfig(packageConfig)
depList, err = provider.GetDependencyList(packageConfig)
if err != nil {
return err
}
if depList == nil {
ui.Log("No dependencies found.")
return nil
}
ui.Title("Expand dependency list...")
depList = expandDepList(depList)
if depList == nil {
return errors.New("Failed to expand dependancy list")
}
ui.Title("Build dependency list...")
depList = provider.BuildDependencyTree(depList)
if depList == nil {
return errors.New("Failed to build dependancy list")
}
ui.Title("Install dependencies...")
installPaths := installDep(path, depList)
ui.Title("Install Binaries...")
err = provider.BinaryInstall(path, installPaths)
if err != nil {
return err
}
ui.Title("Installation done ❤️")
timeElapsed := fmt.Sprintf("%f", time.Since(start).Seconds())
ui.Log(timeElapsed + "s elapsed\n")
return nil
}
================================================
FILE: src/jsVm/jsVm.go
================================================
package jsVm
import (
"encoding/json"
"errors"
"io/ioutil"
"os"
"path/filepath"
"sync"
"time"
"../ui"
"../utils"
"github.com/Masterminds/semver"
"github.com/robertkrimen/otto"
)
var lock = sync.RWMutex{}
var scriptCache = make(map[string]string)
func Run(path string, input utils.Json) (otto.Value, error) {
var err error
var ret otto.Value
lock.Lock()
if scriptCache[path] == "" {
file, err := ioutil.ReadFile(path)
if err != nil {
return otto.UndefinedValue(), err
}
scriptCache[path] = string(file)
}
script := scriptCache[path]
lock.Unlock()
vm := otto.New()
vm.Interrupt = make(chan func(), 1)
Setup(vm)
vm.Set("_DIRNAME", filepath.Dir(path))
for varName, varValue := range input /*.AsObject()*/ {
vm.Set(varName, varValue)
}
ret, err = vm.Run(script)
if err != nil {
ui.Error(err)
return otto.UndefinedValue(), errors.New("Error occured while executing the GS code")
}
return ret, nil
}
func Setup(vm *otto.Otto) {
vm.Set("httpGetJson", func(call otto.FunctionCall) otto.Value {
url, _ := call.Argument(0).ToString()
res := utils.HttpGet(url)
result, _ := vm.ToValue(utils.StringToJSON(string(res)))
return result
})
vm.Set("httpGet", func(call otto.FunctionCall) otto.Value {
url, _ := call.Argument(0).ToString()
res := utils.HttpGet(url)
result, _ := vm.ToValue(string(res))
return result
})
vm.Set("dir", func(call otto.FunctionCall) otto.Value {
glob, _ := call.Argument(0).ToString()
res, _ := utils.Dir(glob)
result, _ := vm.ToValue(res)
return result
})
vm.Set("osSleep", func(call otto.FunctionCall) otto.Value {
timeMs, _ := call.Argument(0).ToInteger()
time.Sleep(time.Duration(timeMs) * time.Millisecond)
result, _ := vm.ToValue(true)
return result
})
vm.Set("readJsonFile", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
b, err := ioutil.ReadFile(path)
if err != nil {
ui.Error(err)
}
result, _ := vm.ToValue(utils.StringToJSON(string(b)))
return result
})
vm.Set("readFile", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
b, err := ioutil.ReadFile(path)
if err != nil {
ui.Error(err)
}
result, _ := vm.ToValue(string(b))
return result
})
vm.Set("removeFiles", func(call otto.FunctionCall) otto.Value {
files, _ := call.Argument(0).Export()
_, isString := files.(string)
if isString {
files = []string{files.(string)}
}
utils.RemoveFiles(files.([]string))
result, _ := vm.ToValue(true)
return result
})
vm.Set("copyFiles", func(call otto.FunctionCall) otto.Value {
files, _ := call.Argument(0).Export()
_, isString := files.(string)
if isString {
files = []string{files.(string)}
}
path, _ := call.Argument(1).ToString()
path = utils.Path(path)
utils.CopyFiles(files.([]string), path)
result, _ := vm.ToValue(true)
return result
})
vm.Set("pwd", func(call otto.FunctionCall) otto.Value {
dir, _ := os.Getwd()
result, _ := vm.ToValue(dir)
return result
})
vm.Set("env", func(call otto.FunctionCall) otto.Value {
name, _ := call.Argument(0).ToString()
value, _ := call.Argument(1).ToString()
if value == "undefined" {
result, _ := vm.ToValue(os.Getenv(name))
return result
} else {
os.Setenv(name, value)
res, _ := vm.ToValue(true)
return res
}
})
vm.Set("exec", func(call otto.FunctionCall) otto.Value {
exec, _ := call.Argument(0).ToString()
args, _ := call.Argument(1).Export()
_, ok := args.([]string)
if !ok {
args = make([]string, 0)
}
err := utils.ExecCommand(exec, args.([]string))
result, _ := vm.ToValue(err)
return result
})
vm.Set("run", func(call otto.FunctionCall) otto.Value {
exec, _ := call.Argument(0).ToString()
args, _ := call.Argument(1).Export()
_, ok := args.([]string)
if !ok {
args = make([]string, 0)
}
res, err := utils.RunCommand(exec, args.([]string))
if err != nil {
ui.Error(err)
result, _ := vm.ToValue(false)
return result
}
if res != "" {
res = res[:len(res)-1]
}
result, _ := vm.ToValue(res)
return result
})
vm.Set("exit", func(call otto.FunctionCall) otto.Value {
code, _ := call.Argument(0).ToInteger()
os.Exit(int(code))
result, _ := vm.ToValue(true)
return result
})
vm.Set("writeJsonFile", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
toExport, _ := call.Argument(1).Export()
file := JsonExport(toExport).(map[string]interface{})
utils.WriteJsonFile(path, file)
result, _ := vm.ToValue(true)
return result
})
vm.Set("writeFile", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
toExport, _ := call.Argument(1).ToString()
err := ioutil.WriteFile(path, []byte(toExport), os.ModePerm)
if err != nil {
ui.Error(err)
}
result, _ := vm.ToValue(true)
return result
})
vm.Set("_OSNAME", utils.OSNAME())
vm.Set("mkdir", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
os.MkdirAll(path, os.ModePerm)
result, _ := vm.ToValue(true)
return result
})
vm.Set("saveLockDep", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
utils.SaveLockDep(path)
result, _ := vm.ToValue(true)
return result
})
vm.Set("fileExists", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
res := utils.FileExists(path)
result, _ := vm.ToValue(res)
return result
})
vm.Set("waitForInput", func(call otto.FunctionCall) otto.Value {
msg, _ := call.Argument(0).ToString()
res := ui.WaitForInput(msg)
result, _ := vm.ToValue(res)
return result
})
vm.Set("waitForMenu", func(call otto.FunctionCall) otto.Value {
msg, _ := call.Argument(0).Export()
res := ui.WaitForMenu(msg.([]string))
result, _ := vm.ToValue(res)
return result
})
vm.Set("waitForKey", func(call otto.FunctionCall) otto.Value {
ui.WaitForKey()
result, _ := vm.ToValue(true)
return result
})
vm.Set("tar", func(call otto.FunctionCall) otto.Value {
files, _ := call.Argument(0).Export()
_, isString := files.(string)
if isString {
files = []string{files.(string)}
}
res, err := utils.Tar(files.([]string))
if err != nil {
ui.Error(err)
}
b, _ := json.Marshal(res)
result, _ := vm.ToValue(utils.StringToJSON(string(b)))
return result
})
vm.Set("readDir", func(call otto.FunctionCall) otto.Value {
path, _ := call.Argument(0).ToString()
path = utils.Path(path)
var filenames = make([]string, 0)
files, _ := utils.ReadDir(path)
for _, file := range files {
filenames = append(filenames, file.Name())
}
result, _ := vm.ToValue(filenames)
return result
})
vm.Set("createSymLink", func(call otto.FunctionCall) otto.Value {
from, _ := call.Argument(0).ToString()
from = utils.Path(from)
to, _ := call.Argument(1).ToString()
to = utils.Path(to)
err := os.Symlink(from, to)
if err != nil {
ui.Error(err)
}
result, _ := vm.ToValue(true)
return result
})
vm.Set("untar", func(call otto.FunctionCall) otto.Value {
var res utils.FileStructure
file, _ := call.Argument(0).ToString()
res, _ = utils.Untar(file)
b, _ := json.Marshal(res)
result, _ := vm.ToValue(utils.StringToJSON(string(b)))
return result
})
vm.Set("unzip", func(call otto.FunctionCall) otto.Value {
var res utils.FileStructure
file, _ := call.Argument(0).ToString()
res, _ = utils.Unzip(file)
b, _ := json.Marshal(res)
result, _ := vm.ToValue(utils.StringToJSON(string(b)))
return result
})
vm.Set("saveFileAt", func(call otto.FunctionCall) otto.Value {
var fs utils.FileStructure
file, _ := call.Argument(0).Export()
path, _ := call.Argument(1).ToString()
path = utils.Path(path)
bytes, _ := json.Marshal(file)
json.Unmarshal(bytes, &fs)
fs.SaveAt(path)
result, _ := vm.ToValue(path)
return result
})
vm.Set("semverInRange", func(call otto.FunctionCall) otto.Value {
rangeStr, _ := call.Argument(0).ToString()
version, _ := call.Argument(1).ToString()
rangeVer, _ := semver.NewConstraint(rangeStr)
sver, _ := semver.NewVersion(version)
value := rangeVer.Check(sver)
result, _ := vm.ToValue(value)
return result
})
vm.Set("semverLatestInRange", func(call otto.FunctionCall) otto.Value {
rangeStr, _ := call.Argument(0).ToString()
versionListUntyped, _ := call.Argument(1).Export()
versionList := utils.ArrString(versionListUntyped)
var version string
var versionSem *semver.Version
rangeVer, _ := semver.NewConstraint(rangeStr)
for _, verCandUnk := range versionList {
verCand := verCandUnk
sver, err := semver.NewVersion(verCand)
if err != nil {
ui.Error(err)
}
if rangeVer.Check(sver) && (versionSem == nil || sver.GreaterThan(versionSem)) {
version = verCand
versionSem = sver
}
}
if version != "" {
result, _ := vm.ToValue(version)
return result
} else {
return otto.UndefinedValue()
}
})
}
func JsonExport(input interface{}) interface{} {
asMap, isMap := input.(map[string]interface{})
asSlice, isSlice := input.([]interface{})
if isMap {
for index, value := range asMap {
asValue, ok := value.(otto.Value)
if ok {
exported, _ := asValue.Export()
asMap[index] = JsonExport(exported)
}
}
return asMap
} else if isSlice {
for index, value := range asSlice {
asValue, ok := value.(otto.Value)
if ok {
exported, _ := asValue.Export()
asSlice[index] = JsonExport(exported)
}
}
return asSlice
} else {
return input
}
}
================================================
FILE: src/plugins.go
================================================
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"./provider"
"./ui"
"./utils"
)
func PluginLink(path string) {
configPath := utils.Path(path + "/gupm.json")
if utils.FileExists(configPath) {
packageConfig := new(utils.GupmEntryPoint)
errConfig := utils.ReadJSON(configPath, &packageConfig)
if errConfig != nil {
ui.Error("Can't read provider configuration")
ui.Error(errConfig)
return
}
pluginFolder := utils.HOMEDIR(".") + utils.Path("/.gupm/plugins/")
os.MkdirAll(pluginFolder, os.ModePerm)
err := os.Symlink(utils.AbsPath(path), pluginFolder+packageConfig.Name)
if err != nil {
ui.Error(err)
}
} else {
ui.Error("Can't find provider configuration")
}
}
func PluginInstall(path string, plugins []string) error {
ui.Title("Install plugin...")
pluginFolder := utils.HOMEDIR(".") + utils.Path("/.gupm/plugins/")
for _, rls := range plugins {
ui.Log(rls)
newDep, err := provider.ResolveDependencyLocation(utils.BuildDependencyFromString("https", rls))
if err != nil {
return err
}
pluginName := filepath.Base(newDep["name"].(string))
if len(strings.Split(pluginName, ":")) > 1 {
pluginName = strings.Split(pluginName, ":")[1]
}
if len(strings.Split(pluginName, "/")) > 1 {
pluginName = strings.Split(pluginName, "/")[1]
}
newDep["path"] = pluginFolder + utils.Path(pluginName)
getRes, errorGD := provider.GetDependency(
newDep["provider"].(string),
newDep["name"].(string),
newDep["version"].(string),
newDep["url"].(string),
newDep["path"].(string),
)
if errorGD != nil {
return errorGD
}
_, errorPGD := provider.PostGetDependency(
newDep["provider"].(string),
newDep["name"].(string),
newDep["version"].(string),
newDep["url"].(string),
newDep["path"].(string),
getRes,
)
if errorPGD != nil {
return errorPGD
}
InstallProject(newDep["path"].(string))
ui.Title("Installation done ❤️")
}
return nil
}
func PluginDelete(path string, plugins []string) {
folders := make([]string, 0)
pluginFolder := utils.HOMEDIR(".") + utils.Path("/.gupm/plugins/")
for _, str := range plugins {
folders = append(folders, pluginFolder+str)
}
utils.RemoveFiles(folders)
fmt.Println("Done deleting.")
}
func PluginCreate(path string) {
fmt.Println("Welcome to the plugin creation assistant")
name := "provider-" + ui.WaitForInput("What is the name of the plugin? provider-")
description := ui.WaitForInput("Enter a description: ")
author := ui.WaitForInput("Enter the author: ")
licence := ui.WaitForInput("Enter the licence (ISC): ")
ppath := utils.Path(path + "/" + name)
os.MkdirAll(ppath, os.ModePerm)
os.MkdirAll(ppath+utils.Path("/docs/repo"), os.ModePerm)
utils.WriteFile(ppath+utils.Path("/gupm.json"), `{
"name": "`+name+`",
"version": "0.0.1",
"description": "`+description+`",
"author": "`+author+`",
"licence": "`+licence+`",
"publish": {
"source": ["."],
"dest": "../docs/repo"
},
"config": {
"default": {
"entrypoint": "gupm.json",
"installPath": "gupm_modules"
}
}
}`)
fmt.Println("creation done.")
}
================================================
FILE: src/provider/bootstrap.go
================================================
package provider
import (
"../defaultProvider"
"../jsVm"
"../utils"
"errors"
// "fmt"
)
func Bootstrap(path string) error {
if Provider != "gupm" {
var file = utils.FileExists(utils.Path(ProviderPath + "/bootstrap.gs"))
if file {
input := make(map[string]interface{})
input["Path"] = path
_, err := jsVm.Run(utils.Path(ProviderPath+"/bootstrap.gs"), input)
if err != nil {
return err
}
} else {
return errors.New("Provider doesn't have any bootstrap function. Please use 'g bootstrap' to use the default bootstrap.")
}
} else {
defaultProvider.Bootstrap(path)
}
return nil
}
================================================
FILE: src/provider/dependencyTree.go
================================================
package provider
func eliminateRedundancy(tree []map[string]interface{}, path map[string]bool) []map[string]interface{} {
var cleanTree = make([]map[string]interface{}, 0)
for index, dep := range tree {
if dep["name"] != nil {
_ = index
depKey := dep["name"].(string) + "@" + dep["version"].(string)
if path[depKey] != true {
cleanTree = append(cleanTree, dep)
}
}
}
for index, dep := range cleanTree {
if dep["name"] != nil {
nextDepList, ok := dep["dependencies"].([]map[string]interface{})
if ok {
depKey := dep["name"].(string) + "@" + dep["version"].(string)
newPath := make(map[string]bool)
for key, value := range path {
newPath[key] = value
}
newPath[depKey] = true
newSubTree := eliminateRedundancy(nextDepList, newPath)
cleanTree[index]["dependencies"] = newSubTree
}
}
}
return cleanTree
}
func flattenDependencyTree(tree []map[string]interface{}, subTree []map[string]interface{}) ([]map[string]interface{}, []map[string]interface{}) {
var cleanTree = make([]map[string]interface{}, 0)
for index, dep := range subTree {
var rootDeps = make(map[string]string)
for _, dep := range tree {
rootDeps[dep["name"].(string)] = dep["version"].(string)
}
if rootDeps[dep["name"].(string)] == "" {
tree = append(tree, dep)
nextDepList, ok := dep["dependencies"].([]map[string]interface{})
if ok {
newTree, newSubTree := flattenDependencyTree(tree, nextDepList)
tree = newTree
subTree[index]["dependencies"] = newSubTree
}
} else if rootDeps[dep["name"].(string)] != dep["version"].(string) {
nextDepList, ok := dep["dependencies"].([]map[string]interface{})
if ok {
newTree, newSubTree := flattenDependencyTree(tree, nextDepList)
tree = newTree
subTree[index]["dependencies"] = newSubTree
}
cleanTree = append(cleanTree, subTree[index])
}
}
return tree, cleanTree
}
func BuildDependencyTree(tree []map[string]interface{}) []map[string]interface{} {
cleanTree := eliminateRedundancy(tree, make(map[string]bool))
for index, dep := range cleanTree {
nextDepList, ok := dep["dependencies"].([]map[string]interface{})
if ok {
newCleanTree, newDepList := flattenDependencyTree(cleanTree, nextDepList)
cleanTree = newCleanTree
cleanTree[index]["dependencies"] = newDepList
}
}
return cleanTree
}
================================================
FILE: src/provider/install.go
================================================
package provider
import (
"io/ioutil"
"os"
"regexp"
"../defaultProvider"
"../jsVm"
"../ui"
"../utils"
)
func BinaryInstall(path string, paths map[string]string) error {
dest := utils.Path(path + "/.bin")
os.RemoveAll(dest)
os.MkdirAll(dest, os.ModePerm)
for pr, prdir := range paths {
depProviderPath := GetProviderPath(pr)
var file = utils.FileExists(depProviderPath + utils.Path("/binaryInstall.gs"))
if pr != "gupm" && file {
input := make(map[string]interface{})
input["Destination"] = dest
input["Source"] = prdir
res, err := jsVm.Run(depProviderPath+utils.Path("/binaryInstall.gs"), input)
if err != nil {
return err
}
_, err1 := res.ToString()
return err1
} else {
return defaultProvider.BinaryInstall(dest, prdir)
}
}
return nil
}
func installDependencySubFolders(path string, depPath string) {
files, _ := utils.ReadDir(path)
for _, file := range files {
if file.IsDir() {
folderPath := utils.Path(depPath + "/" + file.Name())
os.MkdirAll(folderPath, os.ModePerm)
installDependencySubFolders(utils.Path(path+"/"+file.Name()), folderPath)
} else {
isFileExists := false
err := os.Link(utils.Path(path+"/"+file.Name()), utils.Path(depPath+"/"+file.Name()))
if err != nil {
isFileExists, _ = regexp.MatchString(`file exists$`, err.Error())
}
if err != nil && !isFileExists {
if !linkHasErrored {
ui.Error(err)
ui.Error("Error, cannot use hard link on your system. Falling back to copying file (Will be slower!)")
linkHasErrored = true
}
input, err := ioutil.ReadFile(utils.Path(path + "/" + file.Name()))
if err != nil {
ui.Error(err)
return
}
err = ioutil.WriteFile(utils.Path(depPath+"/"+file.Name()), input, 0644)
if err != nil {
ui.Error(err)
return
}
}
}
}
}
func InstallDependency(path string, dep map[string]interface{}) {
depPath := utils.Path(path + "/" + dep["name"].(string))
// if(utils.FileExists(depPath)) {
// // TODO: check version
// } else {
// }
_, ok := dep["path"].(string)
if ok {
os.MkdirAll(utils.Path(depPath), os.ModePerm)
installDependencySubFolders(utils.Path(dep["path"].(string)), depPath)
} else {
ui.Error(dep["name"].(string) + " Cannot be installed.")
}
}
================================================
FILE: src/provider/provider.go
================================================
package provider
import (
"fmt"
"os"
"path/filepath"
"sync"
"../defaultProvider"
"../jsVm"
"../ui"
"../utils"
)
var Provider string
var ProviderPath string
var providerConfigCache = make(map[string]*utils.GupmEntryPoint)
var linkHasErrored = false
var pConfigLock = sync.RWMutex{}
func GetProviderPath(name string) string {
gupmConfig := utils.GupmConfig()
if name == "" {
name = gupmConfig.DefaultProvider
}
if name == "os" {
osName := utils.OSNAME()
if gupmConfig.OsProviders[osName] != "" {
name = gupmConfig.OsProviders[osName]
} else {
ui.Error("No provider set for", osName)
return utils.DIRNAME()
}
}
if name == "gupm" {
return utils.DIRNAME()
} else {
homePlugin := utils.HOMEDIR(".") + utils.Path("/.gupm/plugins/provider-"+name)
localPlugin := utils.DIRNAME() + utils.Path("/plugins/provider-"+name)
if utils.FileExists(homePlugin) {
pluginPath, err := filepath.EvalSymlinks(homePlugin)
if err != nil {
ui.Error(err)
return ""
}
return pluginPath
} else if utils.FileExists(localPlugin) {
return localPlugin
} else {
fmt.Println("Provider cannot be found: " + name + ". Please install it before using it.")
os.Exit(1)
return ""
}
}
}
func InitProvider(provider string) error {
Provider = provider
ProviderPath = GetProviderPath(provider)
if Provider != "" {
providerConfig, err := GetProviderConfig(Provider)
if err != nil {
return err
}
ui.Log("Initialisation OK for " + providerConfig.Name)
} else {
providerConfig, err := GetProviderConfig("gupm")
if err != nil {
return err
}
ui.Log("Initialisation OK for " + providerConfig.Name)
}
return nil
}
func GetProviderConfig(providerName string) (*utils.GupmEntryPoint, error) {
providerConfigPath := GetProviderPath(providerName) + utils.Path("/gupm.json")
pConfigLock.Lock()
if providerConfigCache[providerName] == nil {
config, err := utils.ReadGupmJson(providerConfigPath)
if err != nil {
return nil, err
}
providerConfigCache[providerName] = config
pConfigLock.Unlock()
return config, nil
} else {
config := providerConfigCache[providerName]
pConfigLock.Unlock()
return config, nil
}
}
func GetPackageConfig(path string) (utils.Json, error) {
var file = utils.FileExists(ProviderPath + utils.Path("/getPackageConfig.gs"))
if file {
input := make(map[string]interface{})
input["Path"] = path
res, err := jsVm.Run(ProviderPath+utils.Path("/getPackageConfig.gs"), input)
if err != nil {
return nil, err
}
resObj, err1 := res.Export()
return resObj.(utils.Json), err1
} else {
pc, err := GetProviderConfig(Provider)
if err != nil {
return nil, err
}
return defaultProvider.GetPackageConfig(utils.Path(path + "/" + pc.Config.Default.Entrypoint)), nil
}
}
func PostGetPackageConfig(config utils.Json) (utils.Json, error) {
var file = utils.FileExists(ProviderPath + utils.Path("/postGetPackageConfig.gs"))
if file {
input := make(map[string]interface{})
input["PackageConfig"] = config
res, err := jsVm.Run(ProviderPath+utils.Path("/postGetPackageConfig.gs"), input)
if err != nil {
return nil, err
}
resObj, err1 := res.Export()
return resObj.(utils.Json), err1
} else {
return config, nil
}
}
func SaveDependencyList(path string, depList []map[string]interface{}) error {
var file = utils.FileExists(ProviderPath + utils.Path("/saveDependencyList.gs"))
if file {
input := make(map[string]interface{})
input["Dependencies"] = depList
input["Path"] = path
_, err := jsVm.Run(ProviderPath+utils.Path("/saveDependencyList.gs"), input)
if err != nil {
return err
}
return nil
} else {
return defaultProvider.SaveDependencyList(path, depList)
}
}
func GetDependencyList(config utils.Json) ([]map[string]interface{}, error) {
var file = utils.FileExists(ProviderPath + utils.Path("/getDependencyList.gs"))
if file {
input := make(map[string]interface{})
input["PackageConfig"] = config
res, err := jsVm.Run(ProviderPath+utils.Path("/getDependencyList.gs"), input)
if err != nil {
return nil, err
}
resObj, err1 := res.Export()
resMap, ok := resObj.([]map[string]interface{})
if ok {
return resMap, err1
} else {
return make([]map[string]interface{}, 0), err1
}
} else {
return defaultProvider.GetDependencyList(config), nil
}
}
func ResolveDependencyLocation(dependency map[string]interface{}) (map[string]interface{}, error) {
depProviderPath := GetProviderPath(dependency["provider"].(string))
var file = utils.FileExists(depProviderPath + utils.Path("/resolveDependencyLocation.gs"))
if dependency["provider"].(string) != "gupm" && file {
input := make(map[string]interface{})
input["Dependency"] = dependency
res, err := jsVm.Run(depProviderPath+utils.Path("/resolveDependencyLocation.gs"), input)
if err != nil {
return nil, err
}
resObj, err1 := res.Export()
if resObj == nil {
ui.Error("ERROR Failed to resolve" + dependency["name"].(string) + "Trying again.")
return ResolveDependencyLocation(dependency)
}
return resObj.(map[string]interface{}), err1
} else {
dependency["url"] = dependency["name"].(string)
return dependency, nil
}
}
func ExpandDependency(dependency map[string]interface{}) (map[string]interface{}, error) {
depProviderPath := GetProviderPath(dependency["provider"].(string))
var file = utils.FileExists(depProviderPath + utils.Path("/expandDependency.gs"))
if dependency["provider"].(string) != "gupm" && file {
input := make(map[string]interface{})
input["Dependency"] = dependency
res, err := jsVm.Run(depProviderPath+utils.Path("/expandDependency.gs"), input)
if err != nil {
return nil, err
}
toExport, _ := res.Export()
resObj := jsVm.JsonExport(toExport).(map[string]interface{})
if resObj == nil {
ui.Error("ERROR Failed to resolve" + dependency["name"].(string) + ". Trying again.")
return ExpandDependency(dependency)
}
return resObj, nil
} else {
return defaultProvider.ExpandDependency(dependency)
}
}
func GetDependency(provider string, name string, version string, url string, path string) (string, error) {
depProviderPath := GetProviderPath(provider)
var file = utils.FileExists(depProviderPath + utils.Path("/getDependency.gs"))
if provider != "gupm" && file {
input := make(map[string]interface{})
input["Provider"] = provider
input["Name"] = name
input["Version"] = version
input["Url"] = url
input["Path"] = path
res, err := jsVm.Run(depProviderPath+utils.Path("/getDependency.gs"), input)
if err != nil {
return "", err
}
resStr, err1 := res.ToString()
return resStr, err1
} else {
return defaultProvider.GetDependency(provider, name, version, url, path)
}
}
func PostGetDependency(provider string, name string, version string, url string, path string, result string) (string, error) {
depProviderPath := GetProviderPath(provider)
var file = utils.FileExists(depProviderPath + utils.Path("/postGetDependency.gs"))
if provider != "gupm" && file {
input := make(map[string]interface{})
input["Provider"] = provider
input["Name"] = name
input["Version"] = version
input["Url"] = url
input["Path"] = path
input["Result"] = result
res, err := jsVm.Run(depProviderPath+utils.Path("/postGetDependency.gs"), input)
if err != nil {
return "", err
}
resStr, err1 := res.ToString()
return resStr, err1
} else {
return defaultProvider.PostGetDependency(provider, name, version, url, path, result)
}
}
================================================
FILE: src/provider/publish.go
================================================
package provider
import (
"errors"
"../defaultProvider"
"../jsVm"
"../utils"
// "fmt"
)
func Publish(path string, namespace string) error {
if Provider != "gupm" {
var file = utils.FileExists(utils.Path(ProviderPath + "/publish.gs"))
if file {
input := make(map[string]interface{})
input["Path"] = path
_, err := jsVm.Run(utils.Path(ProviderPath+"/publish.gs"), input)
return err
} else {
return errors.New("Provider doesn't have any publish function. Please use 'g publish' to use the default publish.")
}
} else {
return defaultProvider.Publish(path, namespace)
}
}
================================================
FILE: src/publish.go
================================================
package main
import (
"./provider"
"./ui"
)
func Publish(path string, namespace string) error {
err := provider.InitProvider(Provider)
if err != nil {
return err
}
ui.Title("Publishing package...")
errPub := provider.Publish(path, namespace)
if errPub != nil {
return errPub
} else {
ui.Title("Publish done! ❤️")
}
return nil
}
================================================
FILE: src/removeDependency.go
================================================
package main
import (
"./provider"
"./ui"
"./utils"
)
func remove(slice []map[string]interface{}, s int) []map[string]interface{} {
return append(slice[:s], slice[s+1:]...)
}
func RemoveDependency(path string, rls []string) error {
var err error
var packageConfig utils.Json
var depList []map[string]interface{}
ui.Title("Add dependency...")
err = provider.InitProvider(Provider)
if err != nil {
return err
}
providerConfig, err = provider.GetProviderConfig(Provider)
ui.Error(err)
packageConfig, _ = provider.GetPackageConfig(path)
packageConfig, _ = provider.PostGetPackageConfig(packageConfig)
depList, err = provider.GetDependencyList(packageConfig)
if err != nil {
return err
}
ui.Title("Removing from dependency list...")
for _, str := range rls {
for index, dep := range depList {
if dep["name"].(string) == str {
depList = remove(depList, index)
}
}
}
err = provider.SaveDependencyList(path, depList)
if err != nil {
return err
}
// TODO: Remove from module folder
return nil
}
================================================
FILE: src/self.go
================================================
package main
import (
"./ui"
"./utils"
"io/ioutil"
"os"
"os/exec"
"runtime"
)
// TODO: implemement script-free upgrade for all OSes
func SelfUpgrade() {
SelfUninstall()
if runtime.GOOS != "windows" {
script := utils.HttpGet("https://azukaar.github.io/GuPM/install.sh")
ioutil.WriteFile("TEMP_install.sh", []byte(script), os.ModePerm)
cmd := exec.Command("/bin/sh", "TEMP_install.sh")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Run()
utils.RemoveFiles([]string{"TEMP_install.sh"})
} else {
ui.Error("Upgrade not fully implememnted on windows yet. Please execute windows_installer.exe again")
}
}
func SelfUninstall() {
utils.RemoveFiles([]string{utils.DIRNAME()})
if runtime.GOOS != "windows" {
utils.RemoveFiles([]string{"/usr/local/bin/g", "/bin/g"})
}
}
================================================
FILE: src/test.go
================================================
package main
import (
"os"
"regexp"
"strconv"
"./jsVm"
"./ui"
"./utils"
)
func RunTest(path string) {
_ = jsVm.Run
files := utils.RecursiveFileWalkDir(path)
i := 0
for _, file := range files {
isTest, _ := regexp.MatchString(`\.test\.gs$`, file)
if isTest {
os.MkdirAll(".tmp_test_gupm", os.ModePerm)
utils.CopyFiles([]string{file}, ".tmp_test_gupm/"+strconv.Itoa(i)+".gs")
errch := os.Chdir(".tmp_test_gupm")
if errch != nil {
ui.Error("Could'n execute", file)
Exit(1)
}
_, err := jsVm.Run(strconv.Itoa(i)+".gs", make(map[string]interface{}))
os.Chdir("..")
utils.RemoveFiles([]string{".tmp_test_gupm"})
if err != nil {
ui.Error("Test execution failed:", file)
Exit(1)
}
i++
}
}
ui.Title("Test passed! ❤️")
}
================================================
FILE: src/ui/log.go
================================================
package ui
import (
"bufio"
"errors"
"fmt"
"github.com/fatih/color"
"github.com/gosuri/uilive"
"os"
"strconv"
"sync"
"time"
)
var errorList = make([]string, 0)
var debugList = make([]string, 0)
var currentLog string
var currentTitle string
var progress int
var screenWidth int
var positionToDrawAt int
var logBox = uilive.New()
var lock = sync.RWMutex{}
var errorLock = sync.RWMutex{}
var redrawNeeded = false
var running = true
var isWaitingForInput = false
func Title(log string) {
_ = color.Green
currentTitle = log
currentLog = ""
redrawNeeded = true
}
func Log(log string) {
currentLog = log
redrawNeeded = true
}
func Error(errs ...interface{}) error {
res := ""
for _, err := range errs {
errErr, isErr := err.(error)
errStr, isStr := err.(string)
if isErr && errErr != nil {
res += " " + errErr.Error()
} else if isStr {
res += " " + errStr
}
}
if res != "" {
errorLock.Lock()
errorList = append(errorList, res)
errorLock.Unlock()
if len(errorList) <= 10 {
redrawNeeded = true
}
return errors.New(res)
} else {
return nil
}
}
func Debug(err string) {
debugList = append(debugList, err)
if len(debugList) <= 10 {
Draw()
}
}
func Progress(p int) {
progress = p
redrawNeeded = true
}
// https://github.com/ahmetb/go-cursor/blob/master/cursor.go
var Esc = "\x1b"
func escape(format string, args ...interface{}) string {
return fmt.Sprintf("%s%s", Esc, fmt.Sprintf(format, args...))
}
func moveCursor(x int, y int) {
escape("[%d;%dH", x, y)
}
func init() {
positionToDrawAt = 0
logBox.Start()
go (func() {
for range time.Tick(200 * time.Millisecond) {
if running {
Draw()
}
}
})()
}
func drawTitle() string {
if currentTitle != "" {
title := color.New(color.FgBlue, color.Bold)
return title.Sprintln("🐶 " + currentTitle)
} else {
return ""
}
}
func drawLog() string {
if currentLog != "" {
log := color.New(color.FgGreen)
return log.Sprintln("✓ " + currentLog)
} else {
return ""
}
}
func Stop() {
redrawNeeded = true
running = false
Draw()
}
func WaitForKey() {
isWaitingForInput = true
logBox.Flush()
reader := bufio.NewReader(os.Stdin)
reader.ReadRune()
isWaitingForInput = false
}
func WaitForInput(msg string) string {
isWaitingForInput = true
logBox.Flush()
fmt.Printf(msg)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
var result = scanner.Text()
isWaitingForInput = false
return result
}
if scanner.Err() != nil {
}
return ""
}
func WaitForMenu(msgs []string) int {
lgth := len(msgs)
i := 1
res := 0
for _, msg := range msgs {
fmt.Println(strconv.Itoa(i) + " : " + msg)
i++
}
for res <= 0 || res > lgth {
resString := WaitForInput("Please input choice 1 - " + strconv.Itoa(lgth) + ": ")
res, _ = strconv.Atoi(resString)
}
return res
}
func Draw() {
if !redrawNeeded || isWaitingForInput {
return
}
result := ""
result += drawTitle()
if progress > 0 {
fmt.Print("📦📦")
for i := 0; i < 20; i++ {
if i == progress/5 {
fmt.Print("🐕")
} else {
fmt.Print("-")
}
}
fmt.Println("🏠")
}
result += drawLog()
errorColor := color.New(color.FgRed)
limit := 0
errorLock.RLock()
for _, v := range errorList {
_ = v
if limit == 10 {
result += errorColor.Sprintln("❌❌❌ Too many errors to display...")
limit++
} else if limit < 10 {
result += errorColor.Sprintln("❌ " + v)
limit++
}
}
errorLock.RUnlock()
limit = 0
for _, v := range debugList {
_ = v
if limit == 10 {
result += "Too many debugs..."
limit++
} else if limit < 10 {
result += v
limit++
}
}
lock.Lock()
if running {
fmt.Fprintf(logBox, result)
} else {
fmt.Fprintf(logBox, "\n")
logBox.Stop()
fmt.Println(result)
}
redrawNeeded = false
lock.Unlock()
}
================================================
FILE: src/utils/files.go
================================================
package utils
import (
"os"
"strings"
// "fmt"
"github.com/bmatcuk/doublestar"
"github.com/otiai10/copy"
)
var EmptyFileStructure = FileStructure{}
type FileStructure struct {
Children map[string]FileStructure
Name string
Content []byte
Filetype int
}
func Dir(path string) (matches []string, err error) {
return doublestar.Glob(path)
}
func RemoveFiles(files []string) error {
for _, file := range files {
return os.RemoveAll(file)
}
return nil
}
func CopyFiles(files []string, destination string) error {
for _, file := range files {
return copy.Copy(file, destination)
}
return nil
}
func (g *FileStructure) getOrCreate(path string, options FileStructure) FileStructure {
var folders = strings.Split(path, "/")
var folder = folders[0]
var child, _ = g.Children[folder]
if child.Name == "" {
if len(folders) > 1 {
g.Children[folder] = FileStructure{
Children: make(map[string]FileStructure),
Name: folder,
Filetype: 0,
}
} else {
g.Children[folder] = FileStructure{
Children: make(map[string]FileStructure),
Name: folder,
Filetype: options.Filetype,
Content: options.Content,
}
}
child, _ = g.Children[folder]
}
if len(folders) > 1 {
next := folders[1:]
return child.getOrCreate(strings.Join(next[:], "/"), options)
} else {
return child
}
}
func (g *FileStructure) SaveSelfAt(path string) error {
if g.Filetype == 0 {
newPath := Path(path + "/" + g.Name)
os.MkdirAll(newPath, os.ModePerm)
for _, child := range g.Children {
child.SaveSelfAt(newPath)
}
} else {
filePath := path
if g.Name != "" {
filePath = Path(filePath + "/" + g.Name)
}
f, err := os.OpenFile(filePath, os.O_CREATE|os.O_RDWR, os.FileMode(0777))
if err != nil {
f.Close()
return err
}
if _, err := f.Write(g.Content); err != nil {
f.Close()
return err
}
f.Close()
}
return nil
}
func (g *FileStructure) SaveAt(path string) error {
if g.Filetype == 0 {
os.MkdirAll(Path(path), os.ModePerm)
for _, child := range g.Children {
child.SaveSelfAt(Path(path))
}
}
if g.Filetype == 1 {
g.SaveSelfAt(Path(path))
}
return nil
}
================================================
FILE: src/utils/json.go
================================================
package utils
// import (
// "reflect"
// "fmt"
// )
// type Json map[interface{}]interface {}
type Json map[string]interface{}
// func (j *Json) AsObject() map[string]interface {} {
// res := map[string]interface{}{}
// for i, v := range *j {
// res[i.(string)] = v
// }
// return res
// }
func (j *Json) Contains(test interface{}) bool {
for i := range *j {
if i == test {
return true
}
}
return false
}
func (j *Json) get(index interface{}) interface{} {
return (*j)[index.(string)]
}
// func (j *Json) indexOf(test interface{}) interface{} {
// for i, _ := range *j {
// if(i == test) {
// return true
// }
// }
// return false
// }
================================================
FILE: src/utils/repo.go
================================================
package utils
import (
"io/ioutil"
)
func GetOrCreateRepo(path string) map[string]interface{} {
configPath := path + "/gupm_repo.json"
if !FileExists(configPath) {
baseConfig := `{
"packages": {}
}`
WriteFile(configPath, baseConfig)
return StringToJSON(baseConfig)
}
file, _ := ioutil.ReadFile(configPath)
return StringToJSON(string(file))
}
func SaveRepo(path string, file map[string]interface{}) {
WriteJsonFile(path+"/gupm_repo.json", file)
}
================================================
FILE: src/utils/types.go
================================================
package utils
type GupmEntryPoint struct {
Name string
Version string
WrapInstallFolder string
Git gupmEntryPointGit
Publish gupmEntryPointPublish
Cli gupmEntryPointCliList
Config gupmEntryPointConfigList
Dependencies gupmEntryPointDependenciesList
}
type gupmEntryPointCliList struct {
DefaultProviders map[string]string
Aliases map[string]interface{}
}
type gupmEntryPointGit struct {
Hooks gupmEntryPointGitHooks
}
type gupmEntryPointGitHooks struct {
Precommit interface{}
Prepush interface{}
}
type gupmEntryPointDependenciesList struct {
DefaultProvider string
Default map[string]string
}
type gupmEntryPointConfigList struct {
Default gupmEntryPointConfig
}
type gupmEntryPointConfig struct {
Entrypoint string
InstallPath string
DefaultProvider string
OsProviders map[string]string
}
type gupmEntryPointPublish struct {
Source []string
Dest string
}
================================================
FILE: src/utils/untar.go
================================================
package utils
import "archive/tar"
import "archive/zip"
import "compress/gzip"
import (
"bytes"
"io"
"io/ioutil"
"strings"
)
func Ungz(r string) (FileStructure, error) {
tr, err := gzip.NewReader(strings.NewReader(r))
if err != nil {
return EmptyFileStructure, err
}
defer tr.Close()
buf := new(bytes.Buffer)
buf.ReadFrom(tr)
root := FileStructure{
Children: make(map[string]FileStructure),
Name: tr.Header.Name,
Content: buf.Bytes(),
Filetype: 1,
}
return root, nil
}
func Tar(files []string) (FileStructure, error) {
var buf bytes.Buffer
gzw := gzip.NewWriter(&buf)
tw := tar.NewWriter(gzw)
finalList := make([]string, 0)
for _, file := range files {
if IsDirectory(file) {
finalList = append(finalList, RecursiveFileWalkDir(file)...)
} else {
finalList = append(finalList, file)
}
}
for _, file := range finalList {
content, err := ioutil.ReadFile(file)
if err != nil {
return EmptyFileStructure, err
}
hdr := &tar.Header{
Name: file,
Mode: 0740,
Size: int64(len(content)),
}
if err := tw.WriteHeader(hdr); err != nil {
return EmptyFileStructure, err
}
if _, err := tw.Write([]byte(content)); err != nil {
return EmptyFileStructure, err
}
}
if err := tw.Close(); err != nil {
return EmptyFileStructure, err
}
if err := gzw.Close(); err != nil {
return EmptyFileStructure, err
}
root := FileStructure{
Content: buf.Bytes(),
Filetype: 1,
}
return root, nil
}
func Untar(r string) (FileStructure, error) {
gzr, err := gzip.NewReader(strings.NewReader(r))
root := FileStructure{
Children: make(map[string]FileStructure),
Name: "/",
Filetype: 0,
}
if err != nil {
return EmptyFileStructure, err
}
defer gzr.Close()
tr := tar.NewReader(gzr)
for {
header, err := tr.Next()
switch {
case err == io.EOF:
return root, nil
case err != nil:
return root, err
case header == nil:
continue
}
switch header.Typeflag {
// if its a dir and it doesn't exist create it
case tar.TypeDir:
{
root.getOrCreate(header.Name, FileStructure{
Filetype: 0,
})
}
// if it's a file create it
case tar.TypeReg:
buf := new(bytes.Buffer)
buf.ReadFrom(tr)
root.getOrCreate(header.Name, FileStructure{
Filetype: 1,
Content: buf.Bytes(),
})
}
}
return root, nil
}
func Unzip(r string) (FileStructure, error) {
root := FileStructure{
Children: make(map[string]FileStructure),
Name: "/",
Filetype: 0,
}
tr, _ := zip.NewReader(strings.NewReader(r), int64(len(r)))
for _, f := range tr.File {
// if its a dir and it doesn't exist create it
if f.FileInfo().IsDir() {
root.getOrCreate(f.Name, FileStructure{
Filetype: 0,
})
} else {
rc, _ := f.Open()
buf := new(bytes.Buffer)
buf.ReadFrom(rc)
root.getOrCreate(f.Name, FileStructure{
Filetype: 1,
Content: buf.Bytes(),
})
}
}
return root, nil
}
================================================
FILE: src/utils/utils.go
================================================
package utils
import (
"encoding/json"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path/filepath"
"reflect"
"regexp"
"runtime"
"sync"
"time"
"../ui"
"github.com/mitchellh/go-homedir"
)
type Dependency struct {
Name string
Provider string
Version string
}
func buildCmd(toRun string, args []string) *exec.Cmd {
isNode := regexp.MustCompile(`.js$`)
var cmd *exec.Cmd
bashargs := []string{}
// temporary hack to make windows execute js file with node
if isNode.FindString(toRun) != "" {
bashargs = append(bashargs, toRun)
bashargs = append(bashargs, args...)
cmd = exec.Command("node", bashargs...)
} else {
bashargs = append(bashargs, args...)
cmd = exec.Command(toRun, bashargs...)
}
return cmd
}
func ExecCommand(toRun string, args []string) error {
cmd := buildCmd(toRun, args)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
err := cmd.Run()
return err
}
func ReadGupmJson(path string) (*GupmEntryPoint, error) {
if !FileExists(path) {
return nil, nil
}
config := new(GupmEntryPoint)
errRead := ReadJSON(path, config)
if errRead != nil {
ui.Error("Can't read", path, "check your file")
return nil, errRead
}
return config, nil
}
func RunCommand(toRun string, args []string) (string, error) {
cmd := buildCmd(toRun, args)
res, err := cmd.Output()
if err != nil {
return "", err
}
return string(res), nil
}
func BuildStringFromDependency(dep map[string]interface{}) string {
rep := dep["name"].(string)
if dep["version"] != nil && dep["version"].(string) != "" {
rep += "@" + dep["version"].(string)
}
if dep["provider"] != nil && dep["provider"].(string) != "" {
rep = dep["provider"].(string) + "://" + rep
}
return rep
}
func BuildDependencyFromString(defaultProvider string, dep string) map[string]interface{} {
result := make(map[string]interface{})
step := dep
versionCheck := regexp.MustCompile(`@[\w\.\-\_\^\~]+$`)
tryversion := versionCheck.FindString(step)
if tryversion != "" {
result["version"] = tryversion[1:]
step = versionCheck.ReplaceAllString(step, "")
} else {
result["version"] = "*.*.*"
}
providerCheck := regexp.MustCompile(`^[\w\-\_]+\:\/\/`)
tryprovider := providerCheck.FindString(step)
if tryprovider != "" {
result["provider"] = tryprovider[:len(tryprovider)-3]
step = providerCheck.ReplaceAllString(step, "")
} else {
result["provider"] = defaultProvider
}
result["name"] = step
return result
}
func StringToJSON(b string) map[string]interface{} {
var jsonString map[string]interface{}
json.Unmarshal([]byte(string(b)), &jsonString)
return jsonString
}
func ReadJSON(path string, target interface{}) error {
b, err := os.Open(path) // just pass the file name
if err != nil {
b.Close()
return err
}
defer b.Close()
return json.NewDecoder(b).Decode(target)
}
var numberConnectionOpened = 0
func HttpGet(url string) []byte {
if numberConnectionOpened > 50 {
time.Sleep(1000 * time.Millisecond)
return HttpGet(url)
}
numberConnectionOpened++
resp, httperr := http.Get(url)
if httperr != nil {
numberConnectionOpened--
isRateLimit, _ := regexp.MatchString(`unexpected EOF$`, httperr.Error())
if !isRateLimit {
ui.Error("Error accessing", url, "trying again.", httperr)
}
time.Sleep(1000 * time.Millisecond)
return HttpGet(url)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
numberConnectionOpened--
ui.Error("Error reading HTTP response ", err)
return HttpGet(url)
}
numberConnectionOpened--
return body
}
func FileExists(path string) bool {
_, err := os.Stat(path)
if err == nil {
return true
}
if os.IsNotExist(err) {
return false
}
return true
}
func StringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
func RemoveIndex(s []map[string]interface{}, index int) []map[string]interface{} {
return append(s[:index], s[index+1:]...)
}
func RecursiveFileWalkDir(source string) []string {
result := make([]string, 0)
err := filepath.Walk(source,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
result = append(result, path)
}
return nil
})
if err != nil {
ui.Error(err)
}
return result
}
var lock = sync.RWMutex{}
func ReadDir(path string) ([]os.FileInfo, error) {
lock.Lock()
files, err := ioutil.ReadDir(path)
lock.Unlock()
if err != nil {
ui.Error(err)
return files, err
}
return files, nil
}
func IsDirectory(path string) bool {
fileInfo, err := os.Stat(path)
if err != nil {
return false
}
return fileInfo.IsDir()
}
func HOMEDIR(fallback string) string {
hdir, errH := homedir.Dir()
if errH != nil {
ui.Error(errH)
hdir = fallback
}
return hdir
}
func DIRNAME() string {
ex, err := os.Executable()
exr, err := filepath.EvalSymlinks(ex)
if err != nil {
panic(err)
}
dir := filepath.Dir(exr)
return dir
}
func WriteFile(path string, file string) error {
return ioutil.WriteFile(Path(path), []byte(file), os.ModePerm)
}
func WriteJsonFile(path string, file map[string]interface{}) {
bytes, _ := json.MarshalIndent(file, "", " ")
err := ioutil.WriteFile(path, bytes, os.ModePerm)
if err != nil {
ui.Error(err)
}
}
// TODO: https://blog.golang.org/pipelines
// add proper checksum check
func SaveLockDep(path string) {
ioutil.WriteFile(path+"/.gupm_locked", []byte("1"), os.ModePerm)
}
func AbsPath(rel string) string {
abs, _ := filepath.Abs(rel)
return abs
}
func Path(path string) string {
if runtime.GOOS == "windows" {
return filepath.FromSlash(path)
} else {
return filepath.ToSlash(path)
}
}
func Contains(s interface{}, elem interface{}) bool {
arrV := reflect.ValueOf(s)
if arrV.Kind() == reflect.Slice {
for i := 0; i < arrV.Len(); i++ {
// XXX - panics if slice element points to an unexported struct field
// see https://golang.org/pkg/reflect/#Value.Interface
if arrV.Index(i).Interface() == elem {
return true
}
}
}
return false
}
func ArrString(something interface{}) []string {
_, ok := something.([]string)
if !ok {
res := make([]string, 0)
for _, v := range something.([]interface{}) {
res = append(res, v.(string))
}
return res
} else {
return something.([]string)
}
}
func GupmConfig() gupmEntryPointConfig {
gupmjson, _ := ReadGupmJson(Path(DIRNAME() + "/gupm.json"))
return gupmjson.Config.Default
}
func OSNAME() string {
osName := runtime.GOOS
if osName == "darwin" {
return "mac"
}
return osName
}
================================================
FILE: src/windows/windows_install.go
================================================
package main
import (
"../ui"
"../utils"
"fmt"
)
func main() {
arch := utils.HttpGet("https://azukaar.github.io/GuPM/gupm_windows.tar.gz")
files, _ := utils.Untar(string(arch))
path := ui.WaitForInput("Where do you want to save GuPM? (default C:\\)")
if path == "" {
path = "C:\\"
}
files.SaveAt(path)
fmt.Println("GuPM saved in " + path + ". dont forget to add it to your PATH")
}
================================================
FILE: tests/install/normal.test.gs
================================================
writeJsonFile("gupm.json", {
"dependencies": {
"default": {
}
}
})
var err = exec("../build/dg", ["i", "git://github.com/Masterminds/semver"])
if(err) {
throw new Error(JSON.stringify(err))
}
if (!fileExists('gupm_modules/github.com/Masterminds/semver')) {
throw new Error(1)
}
================================================
FILE: tests/make/nodeps.test.gs
================================================
writeJsonFile("gupm.json", {
"dependencies": {
"default": {
}
}
})
var err = exec("../build/dg", ["make"])
if(err) {
throw new Error(JSON.stringify(err))
}
================================================
FILE: tests/make/normal.test.gs
================================================
writeJsonFile("gupm.json", {
"dependencies": {
"default": {
"git://github.com/Masterminds/semver": "master"
}
}
})
var err = exec("../build/dg", ["make"])
if(err) {
throw new Error(JSON.stringify(err))
}
if (!fileExists('gupm_modules/github.com/Masterminds/semver')) {
throw new Error(1)
}
================================================
FILE: tests/plugins/normal.test.gs
================================================
writeJsonFile("gupm.json", {
"dependencies": {
"default": {
"npm://webpack": "latest"
}
}
})
var err = exec("../build/dg", ["pl", "install", "https://azukaar.github.io/GuPM-official/repo:provider-npm"])
var err2 = exec("../build/dg", ["make"])
if(err || err2) {
throw new Error(JSON.stringify(err))
}
if (!fileExists('node_modules/webpack')) {
throw new Error(1)
}
================================================
FILE: tests/scripts/normal.test.gs
================================================
writeFile("testscript.gs","writeFile('test','it works');")
var err = exec("../build/dg", ["testscript"])
if(err) {
throw new Error(JSON.stringify(err))
}
if (!fileExists('test')) {
throw new Error(1)
}