mirror of
https://github.com/Icinga/icingabeat.git
synced 2025-04-08 17:15:05 +02:00
185 lines
4.7 KiB
Go
185 lines
4.7 KiB
Go
// Licensed to Elasticsearch B.V. under one or more contributor
|
|
// license agreements. See the NOTICE file distributed with
|
|
// this work for additional information regarding copyright
|
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
|
// the Apache License, Version 2.0 (the "License"); you may
|
|
// not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package mage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
"github.com/magefile/mage/sh"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
elasticDocsRepoURL = "https://github.com/elastic/docs.git"
|
|
)
|
|
|
|
type docsBuilder struct{}
|
|
|
|
type asciidocParams struct {
|
|
name string
|
|
indexFile string
|
|
}
|
|
|
|
// DocsOption is a documentation generation option for controlling how the docs
|
|
// are built.
|
|
type DocsOption func(params *asciidocParams)
|
|
|
|
// DocsName specifies the documentation's name (default to BeatName).
|
|
func DocsName(name string) DocsOption {
|
|
return func(params *asciidocParams) {
|
|
params.name = name
|
|
}
|
|
}
|
|
|
|
// DocsIndexFile specifies the index file (defaults to docs/index.asciidoc).
|
|
func DocsIndexFile(file string) DocsOption {
|
|
return func(params *asciidocParams) {
|
|
params.indexFile = file
|
|
}
|
|
}
|
|
|
|
// Docs holds the utilities for building documentation.
|
|
var Docs = docsBuilder{}
|
|
|
|
// FieldDocs generates docs/fields.asciidoc from the specified fields.yml file.
|
|
func (docsBuilder) FieldDocs(fieldsYML string) error {
|
|
// Run the docs_collector.py script.
|
|
ve, err := PythonVirtualenv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
python, err := LookVirtualenvPath(ve, "python")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
esBeats, err := ElasticBeatsDir()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// TODO: Port this script to Go.
|
|
log.Println(">> Generating docs/fields.asciidoc for", BeatName)
|
|
return sh.Run(python, LibbeatDir("scripts/generate_fields_docs.py"),
|
|
fieldsYML, // Path to fields.yml.
|
|
BeatName, // Beat title.
|
|
esBeats, // Path to general beats folder.
|
|
"--output_path", OSSBeatDir()) // It writes to {output_path}/docs/fields.asciidoc.
|
|
}
|
|
|
|
func (b docsBuilder) AsciidocBook(opts ...DocsOption) error {
|
|
params := asciidocParams{
|
|
name: BeatName,
|
|
indexFile: CWD("docs/index.asciidoc"),
|
|
}
|
|
for _, opt := range opts {
|
|
opt(¶ms)
|
|
}
|
|
|
|
repo, err := GetProjectRepoInfo()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cloneDir := CreateDir(filepath.Join(repo.RootDir, "build/elastic_docs_repo"))
|
|
|
|
// Clone if elastic_docs_repo does not exist.
|
|
if _, err := os.Stat(cloneDir); err != nil {
|
|
log.Println("Cloning elastic/docs to", cloneDir)
|
|
if err = sh.Run("git", "clone", "--depth=1", elasticDocsRepoURL, cloneDir); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
log.Println("Using existing elastic/docs at", cloneDir)
|
|
}
|
|
|
|
// Render HTML.
|
|
htmlDir := CWD("build/html_docs", params.name)
|
|
buildDocsScript := filepath.Join(cloneDir, "build_docs")
|
|
args := []string{
|
|
"--chunk=1",
|
|
"--doc", params.indexFile,
|
|
"--out", htmlDir,
|
|
}
|
|
fmt.Println(">> Building HTML docs at", filepath.Join(htmlDir, "index.html"))
|
|
if err := sh.Run(buildDocsScript, args...); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Serve docs with and HTTP server and open the browser.
|
|
if preview, _ := strconv.ParseBool(os.Getenv("PREVIEW")); preview {
|
|
srv := b.servePreview(htmlDir)
|
|
url := "http://" + srv.Addr
|
|
fmt.Println("Serving docs preview at", url)
|
|
b.openBrowser(url)
|
|
|
|
// Wait
|
|
fmt.Println("Ctrl+C to stop")
|
|
sigs := make(chan os.Signal, 1)
|
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
<-sigs
|
|
srv.Shutdown(context.Background())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// open opens the specified URL in the default browser.
|
|
func (docsBuilder) openBrowser(url string) error {
|
|
var cmd string
|
|
var args []string
|
|
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
cmd = "open"
|
|
case "windows":
|
|
cmd = "cmd"
|
|
args = []string{"/c", "start"}
|
|
default:
|
|
cmd = "xdg-open"
|
|
}
|
|
args = append(args, url)
|
|
return exec.Command(cmd, args...).Start()
|
|
}
|
|
|
|
func (docsBuilder) servePreview(dir string) *http.Server {
|
|
server := &http.Server{
|
|
Addr: net.JoinHostPort("localhost", EnvOr("PREVIEW_PORT", "8000")),
|
|
Handler: http.FileServer(http.Dir(dir)),
|
|
}
|
|
|
|
go func() {
|
|
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
panic(errors.Wrap(err, "failed to start docs preview"))
|
|
}
|
|
}()
|
|
|
|
return server
|
|
}
|