get.porter.sh/porter@v1.3.0/mage/docs/docs.go (about)

     1  package docs
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"os/user"
     8  	"path/filepath"
     9  	"strings"
    10  	"time"
    11  
    12  	"get.porter.sh/magefiles/docker"
    13  	"github.com/magefile/mage/mg"
    14  	"github.com/uwu-tools/magex/mgx"
    15  	"github.com/uwu-tools/magex/shx"
    16  )
    17  
    18  var must = shx.CommandBuilder{StopOnError: true}
    19  
    20  const (
    21  	LocalOperatorRepositoryEnv = "PORTER_OPERATOR_REPOSITORY"
    22  	PreviewContainer           = "porter-docs"
    23  
    24  	// DefaultOperatorSourceDir is the directory where the Porter Operator docs
    25  	// are cloned when LocalOperatorRepositoryEnv was not specified.
    26  	DefaultOperatorSourceDir = "docs/sources/operator"
    27  )
    28  
    29  // Build the website in preparation for deploying to the production website on Netlify.
    30  // Uses symlinks so it won't work on Windows. Don't run locally, use DocsPreview instead.
    31  func Docs() {
    32  	mg.SerialDeps(linkOperatorDocs)
    33  
    34  	cmd := must.Command("hugo", "--source", "docs/")
    35  	baseURL := os.Getenv("BASEURL")
    36  	if baseURL != "" {
    37  		cmd.Args("-b", baseURL)
    38  	}
    39  	mgx.Must(cmd.RunV())
    40  }
    41  
    42  func removePreviewContainer() {
    43  	err := docker.RemoveContainer(PreviewContainer)
    44  	mgx.Must(err)
    45  }
    46  
    47  // Preview the website locally using a Docker container.
    48  func DocsPreview() {
    49  	mg.Deps(removePreviewContainer)
    50  	operatorRepo := ensureOperatorRepository()
    51  	operatorDocs, err := filepath.Abs(filepath.Join(operatorRepo, "docs/content"))
    52  	mgx.Must(err)
    53  
    54  	// TODO: run on a random port, and then read the output to get the container id and then retrieve the port used
    55  
    56  	currentUser, err := user.Current()
    57  	if err != nil {
    58  		currentUser = &user.User{Uid: "0", Gid: "0"}
    59  	}
    60  	setDockerUser := fmt.Sprintf("--user=%s:%s", currentUser.Uid, currentUser.Gid)
    61  	pwd, _ := os.Getwd()
    62  	err = must.Run("docker", "run", "-d", "-v", pwd+":/src",
    63  		"-v", operatorDocs+":/src/docs/content/operator",
    64  		setDockerUser,
    65  		"-p", "1313:1313", "--name", PreviewContainer, "-w", "/src/docs",
    66  		"klakegg/hugo:0.78.1-ext-alpine", "server", "-D", "-F", "--noHTTPCache",
    67  		"--watch", "--bind=0.0.0.0")
    68  	mgx.Must(err)
    69  
    70  	for {
    71  		output, _ := must.OutputS("docker", "logs", "porter-docs")
    72  		if strings.Contains(output, "Web Server is available") {
    73  			break
    74  		}
    75  		time.Sleep(time.Second)
    76  	}
    77  
    78  	err = must.Run("open", "http://localhost:1313/docs/")
    79  	mgx.Must(err)
    80  }
    81  
    82  // Build a branch preview of the website.
    83  func DocsBranchPreview() {
    84  	setBranchBaseURL()
    85  	Docs()
    86  }
    87  
    88  func setBranchBaseURL() {
    89  	// Change the branch to a URL safe slug, e.g. release/v1 -> release-v1
    90  	escapedBranch := strings.ReplaceAll(os.Getenv("BRANCH"), "/", "-")
    91  	// Append a trailing / to the URL for use in Hugo
    92  	baseURL := fmt.Sprintf("https://%s.porter.sh/", escapedBranch)
    93  	os.Setenv("BASEURL", baseURL)
    94  }
    95  
    96  // Build a pull request preview of the website.
    97  func DocsPullRequestPreview() {
    98  	setPullRequestBaseURL()
    99  	Docs()
   100  }
   101  
   102  func setPullRequestBaseURL() {
   103  	// Append a trailing / to netlify preview domain name for use in Hugo
   104  	baseURL := fmt.Sprintf("%s/", os.Getenv("DEPLOY_PRIME_URL"))
   105  	os.Setenv("BASEURL", baseURL)
   106  }
   107  
   108  // clone the other doc repos if they don't exist
   109  // use a local copy as defined in PORTER_OPERATOR_REPOSITORY if available
   110  func linkOperatorDocs() {
   111  	// Remove the old symlink in case the source has moved
   112  	operatorSymlink := "docs/content/docs/operator"
   113  	err := os.RemoveAll(operatorSymlink)
   114  	if !os.IsNotExist(err) {
   115  		mgx.Must(err)
   116  	}
   117  
   118  	repoPath := ensureOperatorRepository()
   119  	contentPath, _ := filepath.Abs("docs/content/docs")
   120  	relPath, _ := filepath.Rel(contentPath, filepath.Join(repoPath, "docs/content"))
   121  	log.Println("ln -s", relPath, operatorSymlink)
   122  	mgx.Must(os.Symlink(relPath, operatorSymlink))
   123  }
   124  
   125  // Ensures that we have an operator repository and returns its location
   126  func ensureOperatorRepository() string {
   127  	repoPath, err := ensureOperatorRepositoryIn(os.Getenv(LocalOperatorRepositoryEnv), DefaultOperatorSourceDir)
   128  	mgx.Must(err)
   129  	return repoPath
   130  }
   131  
   132  // Checks if the repository in localRepo exists and return it
   133  // otherwise clone the repository into defaultRepo, updating with the latest changes if already cloned.
   134  func ensureOperatorRepositoryIn(localRepo string, defaultRepo string) (string, error) {
   135  	// Check if we are using a local repo
   136  	if localRepo != "" {
   137  		if _, err := os.Stat(localRepo); err != nil {
   138  			log.Printf("%s %s does not exist, ignoring\n", LocalOperatorRepositoryEnv, localRepo)
   139  			os.Unsetenv(LocalOperatorRepositoryEnv)
   140  		} else {
   141  			log.Printf("Using operator repository at %s\n", localRepo)
   142  			return localRepo, nil
   143  		}
   144  	}
   145  
   146  	// Clone the repo, and ensure it is up-to-date
   147  	cloneDestination, _ := filepath.Abs(defaultRepo)
   148  	_, err := os.Stat(filepath.Join(cloneDestination, ".git"))
   149  	if err != nil && !os.IsNotExist(err) {
   150  		return "", err
   151  	} else if err == nil {
   152  		log.Println("Operator repository already cloned, updating")
   153  		if err = shx.Command("git", "fetch").In(cloneDestination).Run(); err != nil {
   154  			return "", err
   155  		}
   156  		if err = shx.Command("git", "reset", "--hard", "FETCH_HEAD").In(cloneDestination).Run(); err != nil {
   157  			return "", err
   158  		}
   159  		return cloneDestination, nil
   160  	}
   161  
   162  	log.Println("Cloning operator repository")
   163  	os.RemoveAll(cloneDestination) // if the path existed but wasn't a git repo, we want to remove it and start fresh
   164  	if err = shx.Run("git", "clone", "https://github.com/getporter/operator.git", cloneDestination); err != nil {
   165  		return "", err
   166  	}
   167  	return cloneDestination, nil
   168  }