mirror of
https://github.com/kataras/iris.git
synced 2025-12-22 04:17:03 +00:00
Publish the new version ✈️ | Look description please!
# FAQ ### Looking for free support? http://support.iris-go.com https://kataras.rocket.chat/channel/iris ### Looking for previous versions? https://github.com/kataras/iris#version ### Should I upgrade my Iris? Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready. > Iris uses the [vendor directory](https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo) feature, so you get truly reproducible builds, as this method guards against upstream renames and deletes. **How to upgrade**: Open your command-line and execute this command: `go get -u github.com/kataras/iris`. For further installation support, please click [here](http://support.iris-go.com/d/16-how-to-install-iris-web-framework). ### About our new home page http://iris-go.com Thanks to [Santosh Anand](https://github.com/santoshanand) the http://iris-go.com has been upgraded and it's really awesome! [Santosh](https://github.com/santoshanand) is a freelancer, he has a great knowledge of nodejs and express js, Android, iOS, React Native, Vue.js etc, if you need a developer to find or create a solution for your problem or task, please contact with him. The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please! Read more at https://github.com/kataras/iris/blob/master/HISTORY.md Former-commit-id: eec2d71bbe011d6b48d2526eb25919e36e5ad94e
This commit is contained in:
27
typescript/LICENSE
Normal file
27
typescript/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Gerasimos Maropoulos nor the name of his
|
||||
username, kataras, may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
196
typescript/config.go
Normal file
196
typescript/config.go
Normal file
@@ -0,0 +1,196 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package typescript
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris/typescript/npm"
|
||||
)
|
||||
|
||||
var (
|
||||
pathSeparator = string(os.PathSeparator)
|
||||
nodeModules = pathSeparator + "node_modules" + pathSeparator
|
||||
)
|
||||
|
||||
type (
|
||||
// Tsconfig the struct for tsconfig.json
|
||||
Tsconfig struct {
|
||||
CompilerOptions CompilerOptions `json:"compilerOptions"`
|
||||
Exclude []string `json:"exclude"`
|
||||
}
|
||||
|
||||
// CompilerOptions contains all the compiler options used by the tsc (typescript compiler)
|
||||
CompilerOptions struct {
|
||||
Declaration bool `json:"declaration"`
|
||||
Module string `json:"module"`
|
||||
Target string `json:"target"`
|
||||
Watch bool `json:"watch"`
|
||||
Charset string `json:"charset"`
|
||||
Diagnostics bool `json:"diagnostics"`
|
||||
EmitBOM bool `json:"emitBOM"`
|
||||
EmitDecoratorMetadata bool `json:"emitDecoratorMetadata"`
|
||||
ExperimentalDecorators bool `json:"experimentalDecorators"`
|
||||
InlineSourceMap bool `json:"inlineSourceMap"`
|
||||
InlineSources bool `json:"inlineSources"`
|
||||
IsolatedModules bool `json:"isolatedModules"`
|
||||
Jsx string `json:"jsx"`
|
||||
ReactNamespace string `json:"reactNamespace"`
|
||||
ListFiles bool `json:"listFiles"`
|
||||
Locale string `json:"locale"`
|
||||
MapRoot string `json:"mapRoot"`
|
||||
ModuleResolution string `json:"moduleResolution"`
|
||||
NewLine string `json:"newLine"`
|
||||
NoEmit bool `json:"noEmit"`
|
||||
NoEmitOnError bool `json:"noEmitOnError"`
|
||||
NoEmitHelpers bool `json:"noEmitHelpers"`
|
||||
NoImplicitAny bool `json:"noImplicitAny"`
|
||||
NoLib bool `json:"noLib"`
|
||||
NoResolve bool `json:"noResolve"`
|
||||
SkipDefaultLibCheck bool `json:"skipDefaultLibCheck"`
|
||||
OutDir string `json:"outDir"`
|
||||
OutFile string `json:"outFile"`
|
||||
PreserveConstEnums bool `json:"preserveConstEnums"`
|
||||
Pretty bool `json:"pretty"`
|
||||
RemoveComments bool `json:"removeComments"`
|
||||
RootDir string `json:"rootDir"`
|
||||
SourceMap bool `json:"sourceMap"`
|
||||
SourceRoot string `json:"sourceRoot"`
|
||||
StripInternal bool `json:"stripInternal"`
|
||||
SuppressExcessPropertyErrors bool `json:"suppressExcessPropertyErrors"`
|
||||
SuppressImplicitAnyIndexErrors bool `json:"suppressImplicitAnyIndexErrors"`
|
||||
AllowUnusedLabels bool `json:"allowUnusedLabels"`
|
||||
NoImplicitReturns bool `json:"noImplicitReturns"`
|
||||
NoFallthroughCasesInSwitch bool `json:"noFallthroughCasesInSwitch"`
|
||||
AllowUnreachableCode bool `json:"allowUnreachableCode"`
|
||||
ForceConsistentCasingInFileNames bool `json:"forceConsistentCasingInFileNames"`
|
||||
AllowSyntheticDefaultImports bool `json:"allowSyntheticDefaultImports"`
|
||||
AllowJs bool `json:"allowJs"`
|
||||
NoImplicitUseStrict bool `json:"noImplicitUseStrict"`
|
||||
}
|
||||
|
||||
// Config the configs for the Typescript plugin
|
||||
// Has five (5) fields
|
||||
//
|
||||
// 1. Bin: string, the typescript installation directory/typescript/lib/tsc.js, if empty it will search inside global npm modules
|
||||
// 2. Dir: string, Dir set the root, where to search for typescript files/project. Default "./"
|
||||
// 3. Ignore: string, comma separated ignore typescript files/project from these directories. Default "" (node_modules are always ignored)
|
||||
// 4. Tsconfig: &typescript.Tsconfig{}, here you can set all compilerOptions if no tsconfig.json exists inside the 'Dir'
|
||||
// 5. Editor: typescript.Editor("username","password"), if setted then alm-tools browser-based typescript IDE will be available. Defailt is nil
|
||||
Config struct {
|
||||
// Bin the path of the tsc binary file
|
||||
// if empty then the plugin tries to find it
|
||||
Bin string
|
||||
// Dir the client side directory, which typescript (.ts) files are live
|
||||
Dir string
|
||||
// Ignore ignore folders, default is /node_modules/
|
||||
Ignore string
|
||||
// Tsconfig the typescript build configs, including the compiler's options
|
||||
Tsconfig *Tsconfig
|
||||
}
|
||||
)
|
||||
|
||||
// CompilerArgs returns the CompilerOptions' contents of the Tsconfig
|
||||
// it reads the json tags, add '--' at the start of each one and returns an array of strings
|
||||
// this is from file
|
||||
func (tsconfig *Tsconfig) CompilerArgs() []string {
|
||||
val := reflect.ValueOf(tsconfig).Elem().FieldByName("CompilerOptions") // -> for tsconfig *Tsconfig
|
||||
// val := reflect.ValueOf(tsconfig.CompilerOptions)
|
||||
compilerOpts := make([]string, 0) // 0 because we don't know the real valid options yet.
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
typeField := val.Type().Field(i)
|
||||
valueFieldG := val.Field(i)
|
||||
var valueField string
|
||||
// only if it's string or int we need to put that
|
||||
if valueFieldG.Kind() == reflect.String {
|
||||
//if valueFieldG.String() != "" {
|
||||
//valueField = strconv.QuoteToASCII(valueFieldG.String())
|
||||
// }
|
||||
valueField = valueFieldG.String()
|
||||
} else if valueFieldG.Kind() == reflect.Int {
|
||||
if valueFieldG.Int() > 0 {
|
||||
valueField = strconv.Itoa(int(valueFieldG.Int()))
|
||||
}
|
||||
} else if valueFieldG.Kind() == reflect.Bool {
|
||||
valueField = strconv.FormatBool(valueFieldG.Bool())
|
||||
}
|
||||
|
||||
if valueField != "" && valueField != "false" {
|
||||
// var opt string
|
||||
|
||||
// key := typeField.Tag.Get("json")
|
||||
// // it's bool value of true then just --key, for example --watch
|
||||
// if valueField == "true" {
|
||||
// opt = "--" + key
|
||||
// } else {
|
||||
// // it's a string now, for example -m commonjs
|
||||
// opt = "-" + string(key[0]) + " " + valueField
|
||||
// }
|
||||
key := "--" + typeField.Tag.Get("json")
|
||||
compilerOpts = append(compilerOpts, key)
|
||||
// the form is not '--module ES6' but os.Exec should recognise them as arguments
|
||||
// so we need to put the values on the next index
|
||||
if valueField != "true" {
|
||||
// it's a string now, for example -m commonjs
|
||||
compilerOpts = append(compilerOpts, valueField)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return compilerOpts
|
||||
}
|
||||
|
||||
// FromFile reads a file & returns the Tsconfig by its contents
|
||||
func FromFile(tsConfigAbsPath string) (config Tsconfig, err error) {
|
||||
file, err := ioutil.ReadFile(tsConfigAbsPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = Tsconfig{}
|
||||
err = json.Unmarshal(file, &config)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DefaultTsconfig returns the default Tsconfig, with CompilerOptions module: commonjs, target: es5 and ignore the node_modules
|
||||
func DefaultTsconfig() Tsconfig {
|
||||
return Tsconfig{
|
||||
CompilerOptions: CompilerOptions{
|
||||
Module: "commonjs",
|
||||
Target: "ES6",
|
||||
Jsx: "react",
|
||||
ModuleResolution: "classic",
|
||||
Locale: "en",
|
||||
Watch: true,
|
||||
NoImplicitAny: false,
|
||||
SourceMap: false,
|
||||
},
|
||||
Exclude: []string{"node_modules"},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default Options of the Typescript adaptor
|
||||
// Bin and Editor are setting in runtime via the adaptor
|
||||
func DefaultConfig() Config {
|
||||
root, err := os.Getwd()
|
||||
if err != nil {
|
||||
panic("Typescript Adaptor: Cannot get the Current Working Directory !!! [os.getwd()]")
|
||||
}
|
||||
compilerTsConfig := DefaultTsconfig()
|
||||
c := Config{
|
||||
Dir: root + pathSeparator,
|
||||
Ignore: nodeModules,
|
||||
Tsconfig: &compilerTsConfig,
|
||||
}
|
||||
c.Bin = npm.NodeModuleAbs("typescript/lib/tsc.js")
|
||||
return c
|
||||
}
|
||||
51
typescript/editor/LICENSE
Normal file
51
typescript/editor/LICENSE
Normal file
@@ -0,0 +1,51 @@
|
||||
Copyright (c) 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Gerasimos Maropoulos nor the name of his
|
||||
username, kataras, may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Third-Parties:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Basarat Ali Syed
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
50
typescript/editor/config.go
Normal file
50
typescript/editor/config.go
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package editor
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// Default values for the configuration
|
||||
const (
|
||||
DefaultPort = 4444
|
||||
)
|
||||
|
||||
// Config the configs for the Editor plugin
|
||||
type Config struct {
|
||||
// Hostname if empty used the iris server's hostname
|
||||
Hostname string
|
||||
// Port if 0 4444
|
||||
Port int
|
||||
// KeyFile the key file(ssl optional)
|
||||
KeyFile string
|
||||
// CertFile the cert file (ssl optional)
|
||||
CertFile string
|
||||
// WorkingDir if empty "./"
|
||||
WorkingDir string
|
||||
// Username defaults to empty, you should set this
|
||||
Username string
|
||||
// Password defaults to empty, you should set this
|
||||
Password string
|
||||
// DisableOutput set that to true if you don't care about alm-tools' messages
|
||||
// they are useful because that the default value is "false"
|
||||
DisableOutput bool
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default configs for the Editor plugin
|
||||
func DefaultConfig() Config {
|
||||
// explicit
|
||||
return Config{
|
||||
Hostname: "",
|
||||
Port: 4444,
|
||||
KeyFile: "",
|
||||
CertFile: "",
|
||||
WorkingDir: "." + string(os.PathSeparator), // alm-tools should end with path separator.
|
||||
Username: "",
|
||||
Password: "",
|
||||
DisableOutput: false,
|
||||
}
|
||||
}
|
||||
222
typescript/editor/editor.go
Normal file
222
typescript/editor/editor.go
Normal file
@@ -0,0 +1,222 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package editor
|
||||
|
||||
// +------------------------------------------------------------+
|
||||
// | Editor usage |
|
||||
// +------------------------------------------------------------+
|
||||
//
|
||||
// import "github.com/kataras/iris/typescript/editor"
|
||||
// [...]
|
||||
//
|
||||
// app := iris.New()
|
||||
// e := editor.New(editor.Config{})
|
||||
// e.Attach(app)
|
||||
//
|
||||
// [...]
|
||||
// app.Run(iris.Addr(":8080"))
|
||||
|
||||
//
|
||||
// +------------------------------------------------------------+
|
||||
// | General notes for authentication |
|
||||
// +------------------------------------------------------------+
|
||||
//
|
||||
// The Authorization specifies the authentication mechanism (in this case Basic) followed by the username and password.
|
||||
// Although, the string aHR0cHdhdGNoOmY= may look encrypted it is simply a base64 encoded version of <username>:<password>.
|
||||
// Would be readily available to anyone who could intercept the HTTP request.
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/core/host"
|
||||
"github.com/kataras/iris/typescript/npm"
|
||||
)
|
||||
|
||||
type (
|
||||
// Editor is the alm-tools adaptor.
|
||||
//
|
||||
// It holds a logger from the iris' station
|
||||
// username,password for basic auth
|
||||
// directory which the client side code is
|
||||
// keyfile,certfile for TLS listening
|
||||
// and a host which is listening for
|
||||
Editor struct {
|
||||
config *Config
|
||||
log func(format string, a ...interface{})
|
||||
enabled bool // default true
|
||||
// after alm started
|
||||
process *os.Process
|
||||
debugOutput io.Writer
|
||||
}
|
||||
)
|
||||
|
||||
// New creates and returns an Editor Plugin instance
|
||||
func New(cfg ...Config) *Editor {
|
||||
c := DefaultConfig()
|
||||
if len(cfg) > 0 {
|
||||
c = cfg[0]
|
||||
}
|
||||
c.WorkingDir = validateWorkingDir(c.WorkingDir) // add "/" if not exists
|
||||
|
||||
return &Editor{
|
||||
enabled: true,
|
||||
config: &c,
|
||||
}
|
||||
}
|
||||
|
||||
// User set a user, accepts two parameters: username (string), string (string)
|
||||
func (e *Editor) User(username string, password string) *Editor {
|
||||
e.config.Username = username
|
||||
e.config.Password = password
|
||||
return e
|
||||
}
|
||||
|
||||
func validateWorkingDir(workingDir string) string {
|
||||
l := workingDir[len(workingDir)-1]
|
||||
|
||||
if l != '/' && l != os.PathSeparator {
|
||||
workingDir += "/"
|
||||
}
|
||||
return workingDir
|
||||
}
|
||||
|
||||
// Dir sets the directory which the client side source code alive
|
||||
func (e *Editor) Dir(workingDir string) *Editor {
|
||||
e.config.WorkingDir = validateWorkingDir(workingDir)
|
||||
return e
|
||||
}
|
||||
|
||||
// Port sets the port (int) for the editor adaptor's standalone server
|
||||
func (e *Editor) Port(port int) *Editor {
|
||||
e.config.Port = port
|
||||
return e
|
||||
}
|
||||
|
||||
// SetEnable if true enables the editor adaptor, otherwise disables it
|
||||
func (e *Editor) SetEnable(enable bool) {
|
||||
e.enabled = enable
|
||||
}
|
||||
|
||||
// DisableOutput call that if you don't care about alm-tools' messages
|
||||
// they are useful because that the default configuration shows them
|
||||
func (e *Editor) DisableOutput() {
|
||||
e.config.DisableOutput = true
|
||||
}
|
||||
|
||||
// GetDescription EditorPlugin is a bridge between Iris and the alm-tools, the browser-based IDE for client-side sources.
|
||||
func (e *Editor) GetDescription() string {
|
||||
return "A bridge between Iris and the alm-tools, the browser-based IDE."
|
||||
}
|
||||
|
||||
// we use that editorWriter to prefix the editor's output with "Editor Adaptor: "
|
||||
type editorWriter struct {
|
||||
underline io.Writer
|
||||
}
|
||||
|
||||
// build runs before the server's listens, creates the listener ( use of port parent hostname:DefaultPort if not exist)
|
||||
func (e *Editor) build(s *iris.Application) {
|
||||
e.log = s.Log
|
||||
if e.config.Hostname == "" {
|
||||
e.config.Hostname = "0.0.0.0"
|
||||
}
|
||||
|
||||
if e.config.Port <= 0 {
|
||||
e.config.Port = DefaultPort
|
||||
}
|
||||
|
||||
if s, err := filepath.Abs(e.config.WorkingDir); err == nil {
|
||||
e.config.WorkingDir = s
|
||||
}
|
||||
|
||||
e.start()
|
||||
}
|
||||
|
||||
// close kills the editor's server when Iris is closed
|
||||
func (e *Editor) close(s *iris.Application) {
|
||||
if e.process != nil {
|
||||
err := e.process.Kill()
|
||||
if err != nil {
|
||||
e.log("error while trying to terminate the Editor,please kill this process by yourself, process id: %d", e.process.Pid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// start starts the job
|
||||
func (e *Editor) start() {
|
||||
if e.config.Username == "" || e.config.Password == "" {
|
||||
e.log("error before running alm-tools. You have to set username & password for security reasons, otherwise this adaptor won't run.")
|
||||
return
|
||||
}
|
||||
|
||||
if !npm.NodeModuleExists("alm/bin/alm") {
|
||||
e.log("installing alm-tools, please wait...")
|
||||
res := npm.NodeModuleInstall("alm")
|
||||
if res.Error != nil {
|
||||
e.log(res.Error.Error())
|
||||
return
|
||||
}
|
||||
e.log(res.Message)
|
||||
}
|
||||
|
||||
cmd := npm.CommandBuilder("node", npm.NodeModuleAbs("alm/src/server.js"))
|
||||
cmd.AppendArguments("-a", e.config.Username+":"+e.config.Password,
|
||||
"-h", e.config.Hostname, "-t", strconv.Itoa(e.config.Port), "-d", e.config.WorkingDir)
|
||||
// for auto-start in the browser: cmd.AppendArguments("-o")
|
||||
if e.config.KeyFile != "" && e.config.CertFile != "" {
|
||||
cmd.AppendArguments("--httpskey", e.config.KeyFile, "--httpscert", e.config.CertFile)
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
// when debug is not disabled
|
||||
// show any messages to the user( they are useful here)
|
||||
// to the io.Writer that iris' user is defined from configuration
|
||||
if !e.config.DisableOutput {
|
||||
|
||||
outputReader, err := cmd.StdoutPipe()
|
||||
if err == nil {
|
||||
outputScanner := bufio.NewScanner(outputReader)
|
||||
|
||||
go func() {
|
||||
for outputScanner.Scan() {
|
||||
e.log(prefix + outputScanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
errReader, err := cmd.StderrPipe()
|
||||
if err == nil {
|
||||
errScanner := bufio.NewScanner(errReader)
|
||||
go func() {
|
||||
for errScanner.Scan() {
|
||||
e.log(prefix + errScanner.Text())
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := cmd.Start()
|
||||
if err != nil {
|
||||
e.log(prefix + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// no need, alm-tools post these
|
||||
// e.logger.Printf("Editor is running at %s:%d | %s", e.config.Hostname, e.config.Port, e.config.WorkingDir)
|
||||
}
|
||||
|
||||
// Attach adapts the editor to one or more Iris instance(s).
|
||||
func (e *Editor) Attach(app *iris.Application) {
|
||||
|
||||
e.build(app)
|
||||
|
||||
app.Scheduler.Schedule(host.OnInterrupt(func(proc host.TaskProcess) {
|
||||
e.close(app)
|
||||
}))
|
||||
}
|
||||
118
typescript/npm/exec.go
Normal file
118
typescript/npm/exec.go
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package npm // #nosec
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// PathSeparator is the string of os.PathSeparator
|
||||
PathSeparator = string(os.PathSeparator)
|
||||
)
|
||||
|
||||
type (
|
||||
// Cmd is a custom struch which 'implements' the *exec.Cmd
|
||||
Cmd struct {
|
||||
*exec.Cmd
|
||||
}
|
||||
)
|
||||
|
||||
// Arguments sets the command line arguments, including the command as Args[0].
|
||||
// If the args parameter is empty or nil, Run uses {Path}.
|
||||
//
|
||||
// In typical use, both Path and args are set by calling Command.
|
||||
func (cmd *Cmd) Arguments(args ...string) *Cmd {
|
||||
cmd.Cmd.Args = append(cmd.Cmd.Args[0:1], args...) //we need the first argument which is the command
|
||||
return cmd
|
||||
}
|
||||
|
||||
// AppendArguments appends the arguments to the exists
|
||||
func (cmd *Cmd) AppendArguments(args ...string) *Cmd {
|
||||
cmd.Cmd.Args = append(cmd.Cmd.Args, args...)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ResetArguments resets the arguments
|
||||
func (cmd *Cmd) ResetArguments() *Cmd {
|
||||
cmd.Args = cmd.Args[0:1] //keep only the first because is the command
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Directory sets the working directory of the command.
|
||||
// If workingDirectory is the empty string, Run runs the command in the
|
||||
// calling process's current directory.
|
||||
func (cmd *Cmd) Directory(workingDirectory string) *Cmd {
|
||||
cmd.Cmd.Dir = workingDirectory
|
||||
return cmd
|
||||
}
|
||||
|
||||
// CommandBuilder creates a Cmd object and returns it
|
||||
// accepts 2 parameters, one is optionally
|
||||
// first parameter is the command (string)
|
||||
// second variatic parameter is the argument(s) (slice of string)
|
||||
//
|
||||
// the difference from the normal Command function is that you can re-use this Cmd, it doesn't execute until you call its Command function
|
||||
func CommandBuilder(command string, args ...string) *Cmd {
|
||||
return &Cmd{Cmd: exec.Command(command, args...)}
|
||||
}
|
||||
|
||||
//the below is just for exec.Command:
|
||||
|
||||
// Command executes a command in shell and returns it's output, it's block version
|
||||
func Command(command string, a ...string) (output string, err error) {
|
||||
var out []byte
|
||||
//if no args given, try to get them from the command
|
||||
if len(a) == 0 {
|
||||
commandArgs := strings.Split(command, " ")
|
||||
for _, commandArg := range commandArgs {
|
||||
if commandArg[0] == '-' { // if starts with - means that this is an argument, append it to the arguments
|
||||
a = append(a, commandArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
out, err = exec.Command(command, a...).Output()
|
||||
|
||||
if err == nil {
|
||||
output = string(out)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MustCommand executes a command in shell and returns it's output, it's block version. It panics on an error
|
||||
func MustCommand(command string, a ...string) (output string) {
|
||||
var out []byte
|
||||
var err error
|
||||
if len(a) == 0 {
|
||||
commandArgs := strings.Split(command, " ")
|
||||
for _, commandArg := range commandArgs {
|
||||
if commandArg[0] == '-' { // if starts with - means that this is an argument, append it to the arguments
|
||||
a = append(a, commandArg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out, err = exec.Command(command, a...).Output()
|
||||
if err != nil {
|
||||
argsToString := strings.Join(a, " ")
|
||||
panic(fmt.Sprintf("\nError running the command %s", command+" "+argsToString))
|
||||
}
|
||||
|
||||
output = string(out)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Exists returns true if directory||file exists
|
||||
func Exists(dir string) bool {
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
128
typescript/npm/npm.go
Normal file
128
typescript/npm/npm.go
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package npm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// nodeModulesPath is the path of the root npm modules
|
||||
// Ex: C:\\Users\\kataras\\AppData\\Roaming\\npm\\node_modules
|
||||
nodeModulesPath string
|
||||
)
|
||||
|
||||
type (
|
||||
// NodeModuleResult holds Message and Error, if error != nil then the npm command has failed
|
||||
NodeModuleResult struct {
|
||||
// Message the message (string)
|
||||
Message string
|
||||
// Error the error (if any)
|
||||
Error error
|
||||
}
|
||||
)
|
||||
|
||||
// NodeModulesPath sets the root directory for the node_modules and returns that
|
||||
func NodeModulesPath() string {
|
||||
if nodeModulesPath == "" {
|
||||
nodeModulesPath = MustCommand("npm", "root", "-g") //here it ends with \n we have to remove it
|
||||
nodeModulesPath = nodeModulesPath[0 : len(nodeModulesPath)-1]
|
||||
}
|
||||
return nodeModulesPath
|
||||
}
|
||||
|
||||
func success(output string, a ...interface{}) NodeModuleResult {
|
||||
return NodeModuleResult{fmt.Sprintf(output, a...), nil}
|
||||
}
|
||||
|
||||
func fail(errMsg string, a ...interface{}) NodeModuleResult {
|
||||
return NodeModuleResult{"", fmt.Errorf("\n"+errMsg, a...)}
|
||||
}
|
||||
|
||||
// Output returns the error message if result.Error exists, otherwise returns the result.Message
|
||||
func (res NodeModuleResult) Output() (out string) {
|
||||
if res.Error != nil {
|
||||
out = res.Error.Error()
|
||||
} else {
|
||||
out = res.Message
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NodeModuleInstall installs a module
|
||||
func NodeModuleInstall(moduleName string) NodeModuleResult {
|
||||
finish := make(chan bool)
|
||||
|
||||
go func() {
|
||||
print("\n|")
|
||||
print("_")
|
||||
print("|")
|
||||
|
||||
for {
|
||||
select {
|
||||
case v := <-finish:
|
||||
{
|
||||
if v {
|
||||
print("\010\010\010") //remove the loading chars
|
||||
close(finish)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
default:
|
||||
print("\010\010-")
|
||||
time.Sleep(time.Second / 2)
|
||||
print("\010\\")
|
||||
time.Sleep(time.Second / 2)
|
||||
print("\010|")
|
||||
time.Sleep(time.Second / 2)
|
||||
print("\010/")
|
||||
time.Sleep(time.Second / 2)
|
||||
print("\010-")
|
||||
time.Sleep(time.Second / 2)
|
||||
print("|")
|
||||
}
|
||||
}
|
||||
|
||||
}()
|
||||
out, err := Command("npm", "install", moduleName, "-g")
|
||||
finish <- true
|
||||
if err != nil {
|
||||
return fail("Error installing module %s. Trace: %s", moduleName, err.Error())
|
||||
}
|
||||
|
||||
return success("\n%s installed %s", moduleName, out)
|
||||
|
||||
}
|
||||
|
||||
// NodeModuleUnistall removes a module
|
||||
func NodeModuleUnistall(moduleName string) NodeModuleResult {
|
||||
out, err := Command("npm", "unistall", "-g", moduleName)
|
||||
if err != nil {
|
||||
return fail("Error unstalling module %s. Trace: %s", moduleName, err.Error())
|
||||
}
|
||||
return success("\n %s unistalled %s", moduleName, out)
|
||||
|
||||
}
|
||||
|
||||
// NodeModuleAbs returns the absolute path of the global node_modules directory + relative
|
||||
func NodeModuleAbs(relativePath string) string {
|
||||
return NodeModulesPath() + PathSeparator + strings.Replace(relativePath, "/", PathSeparator, -1)
|
||||
}
|
||||
|
||||
// NodeModuleExists returns true if a module exists
|
||||
// here we have two options
|
||||
//1 . search by command something like npm -ls -g --depth=x
|
||||
//2. search on files, we choose the second
|
||||
func NodeModuleExists(executableRelativePath string) bool {
|
||||
execAbsPath := NodeModuleAbs(executableRelativePath)
|
||||
if execAbsPath == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return Exists(execAbsPath)
|
||||
}
|
||||
229
typescript/typescript.go
Normal file
229
typescript/typescript.go
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright 2017 Gerasimos Maropoulos, ΓΜ. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package typescript provides a typescript compiler with hot-reloader
|
||||
// and optionally a cloud-based editor, called 'alm-tools'.
|
||||
// typescript (by microsoft) and alm-tools (by @basarat) have their own (open-source) licenses
|
||||
// the tools are not used directly by this adaptor, but it's good to know where you can find
|
||||
// the software.
|
||||
package typescript
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/typescript/npm"
|
||||
)
|
||||
|
||||
type (
|
||||
// Typescript contains the unique iris' typescript loader, holds all necessary fields & methods.
|
||||
Typescript struct {
|
||||
Config *Config
|
||||
// taken from framework
|
||||
log func(format string, a ...interface{})
|
||||
}
|
||||
)
|
||||
|
||||
// New creates & returns a new instnace typescript plugin
|
||||
func New() *Typescript {
|
||||
c := DefaultConfig()
|
||||
|
||||
if !strings.Contains(c.Ignore, nodeModules) {
|
||||
c.Ignore += "," + nodeModules
|
||||
}
|
||||
|
||||
return &Typescript{Config: &c}
|
||||
}
|
||||
|
||||
// implementation
|
||||
|
||||
func (t *Typescript) start() {
|
||||
|
||||
if t.hasTypescriptFiles() {
|
||||
//Can't check if permission denied returns always exists = true....
|
||||
|
||||
if !npm.NodeModuleExists(t.Config.Bin) {
|
||||
t.log("installing typescript, please wait...")
|
||||
res := npm.NodeModuleInstall("typescript")
|
||||
if res.Error != nil {
|
||||
t.log(res.Error.Error())
|
||||
return
|
||||
}
|
||||
t.log(res.Message)
|
||||
}
|
||||
|
||||
projects := t.getTypescriptProjects()
|
||||
if len(projects) > 0 {
|
||||
watchedProjects := 0
|
||||
//typescript project (.tsconfig) found
|
||||
for _, project := range projects {
|
||||
cmd := npm.CommandBuilder("node", t.Config.Bin, "-p", project[0:strings.LastIndex(project, npm.PathSeparator)]) //remove the /tsconfig.json)
|
||||
projectConfig, perr := FromFile(project)
|
||||
if perr != nil {
|
||||
t.log("error while trying to read tsconfig: %s", perr.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
if projectConfig.CompilerOptions.Watch {
|
||||
watchedProjects++
|
||||
// if has watch : true then we have to wrap the command to a goroutine (I don't want to use the .Start here)
|
||||
go func() {
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.log(err.Error())
|
||||
return
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.log(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// t.log("%d Typescript project(s) compiled ( %d monitored by a background file watcher", len(projects), watchedProjects)
|
||||
} else {
|
||||
//search for standalone typescript (.ts) files and compile them
|
||||
files := t.getTypescriptFiles()
|
||||
if len(files) > 0 {
|
||||
/* watchedFiles := 0
|
||||
if t.Config.Tsconfig.CompilerOptions.Watch {
|
||||
watchedFiles = len(files)
|
||||
}*/
|
||||
//it must be always > 0 if we came here, because of if hasTypescriptFiles == true.
|
||||
for _, file := range files {
|
||||
absPath, err := filepath.Abs(file)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
//these will be used if no .tsconfig found.
|
||||
// cmd := npm.CommandBuilder("node", t.Config.Bin)
|
||||
// cmd.Arguments(t.Config.Bin, t.Config.Tsconfig.CompilerArgs()...)
|
||||
// cmd.AppendArguments(absPath)
|
||||
compilerArgs := t.Config.Tsconfig.CompilerArgs()
|
||||
cmd := npm.CommandBuilder("node", t.Config.Bin)
|
||||
for _, s := range compilerArgs {
|
||||
cmd.AppendArguments(s)
|
||||
}
|
||||
cmd.AppendArguments(absPath)
|
||||
go func() {
|
||||
compilerMsgB, _ := cmd.Output()
|
||||
compilerMsg := string(compilerMsgB)
|
||||
cmd.Args = cmd.Args[0 : len(cmd.Args)-1] //remove the last, which is the file
|
||||
|
||||
if strings.Contains(compilerMsg, "error") {
|
||||
t.log(compilerMsg)
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
}
|
||||
// t.log("%d Typescript file(s) compiled ( %d monitored by a background file watcher )", len(files), watchedFiles)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Typescript) hasTypescriptFiles() bool {
|
||||
root := t.Config.Dir
|
||||
ignoreFolders := strings.Split(t.Config.Ignore, ",")
|
||||
hasTs := false
|
||||
if !npm.Exists(root) {
|
||||
t.log("typescript error: directory '%s' couldn't be found,\nplease specify a valid path for your *.ts files", root)
|
||||
return false
|
||||
}
|
||||
// ignore error
|
||||
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
|
||||
|
||||
if fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
for i := range ignoreFolders {
|
||||
if strings.Contains(path, ignoreFolders[i]) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(path, ".ts") {
|
||||
hasTs = true
|
||||
return errors.New("Typescript found, hope that will stop here")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return hasTs
|
||||
}
|
||||
|
||||
func (t *Typescript) getTypescriptProjects() []string {
|
||||
var projects []string
|
||||
ignoreFolders := strings.Split(t.Config.Ignore, ",")
|
||||
|
||||
root := t.Config.Dir
|
||||
//t.logger.Printf("\nSearching for typescript projects in %s", root)
|
||||
|
||||
// ignore error
|
||||
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
|
||||
if fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
for i := range ignoreFolders {
|
||||
if strings.Contains(path, ignoreFolders[i]) {
|
||||
//t.logger.Println(path + " ignored")
|
||||
return filepath.SkipDir
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, npm.PathSeparator+"tsconfig.json") {
|
||||
//t.logger.Printf("\nTypescript project found in %s", path)
|
||||
projects = append(projects, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return projects
|
||||
}
|
||||
|
||||
// this is being called if getTypescriptProjects return 0 len, then we are searching for files using that:
|
||||
func (t *Typescript) getTypescriptFiles() []string {
|
||||
var files []string
|
||||
ignoreFolders := strings.Split(t.Config.Ignore, ",")
|
||||
|
||||
root := t.Config.Dir
|
||||
|
||||
// ignore error
|
||||
filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
|
||||
if fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
for i := range ignoreFolders {
|
||||
if strings.Contains(path, ignoreFolders[i]) {
|
||||
//t.logger.Println(path + " ignored")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasSuffix(path, ".ts") {
|
||||
//t.logger.Printf("\nTypescript file found in %s", path)
|
||||
files = append(files, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return files
|
||||
}
|
||||
|
||||
// Attach attaches the typescript to one or more Iris instance(s).
|
||||
func (t *Typescript) Attach(app *iris.Application) {
|
||||
t.log = app.Log
|
||||
t.start()
|
||||
}
|
||||
Reference in New Issue
Block a user