github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/setting/repository.go (about)

     1  // Copyright 2023 The GitBundle Inc. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // Use of this source code is governed by a MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package setting
     7  
     8  import (
     9  	"os/exec"
    10  	"path"
    11  	"path/filepath"
    12  	"strings"
    13  
    14  	"github.com/gitbundle/modules/log"
    15  )
    16  
    17  // enumerates all the policy repository creating
    18  const (
    19  	RepoCreatingLastUserVisibility = "last"
    20  	RepoCreatingPrivate            = "private"
    21  	RepoCreatingPublic             = "public"
    22  )
    23  
    24  // ItemsPerPage maximum items per page in forks, watchers and stars of a repo
    25  const ItemsPerPage = 40
    26  
    27  // Repository settings
    28  var (
    29  	Repository = struct {
    30  		DetectedCharsetsOrder                   []string
    31  		DetectedCharsetScore                    map[string]int `ini:"-"`
    32  		AnsiCharset                             string
    33  		ForcePrivate                            bool
    34  		DefaultPrivate                          string
    35  		DefaultPushCreatePrivate                bool
    36  		MaxCreationLimit                        int
    37  		PreferredLicenses                       []string
    38  		DisableHTTPGit                          bool
    39  		AccessControlAllowOrigin                string
    40  		UseCompatSSHURI                         bool
    41  		DefaultCloseIssuesViaCommitsInAnyBranch bool
    42  		EnablePushCreateUser                    bool
    43  		EnablePushCreateOrg                     bool
    44  		DisabledRepoUnits                       []string
    45  		DefaultRepoUnits                        []string
    46  		PrefixArchiveFiles                      bool
    47  		DisableMigrations                       bool
    48  		DisableStars                            bool `ini:"DISABLE_STARS"`
    49  		DefaultBranch                           string
    50  		AllowAdoptionOfUnadoptedRepositories    bool
    51  		AllowDeleteOfUnadoptedRepositories      bool
    52  		DisableDownloadSourceArchives           bool
    53  
    54  		// Repository editor settings
    55  		Editor struct {
    56  			LineWrapExtensions   []string
    57  			PreviewableFileModes []string
    58  		} `ini:"-"`
    59  
    60  		// Repository upload settings
    61  		Upload struct {
    62  			Enabled      bool
    63  			TempPath     string
    64  			AllowedTypes string
    65  			FileMaxSize  int64
    66  			MaxFiles     int
    67  		} `ini:"-"`
    68  
    69  		// Repository local settings
    70  		Local struct {
    71  			LocalCopyPath string
    72  		} `ini:"-"`
    73  
    74  		// Pull request settings
    75  		PullRequest struct {
    76  			WorkInProgressPrefixes                   []string
    77  			CloseKeywords                            []string
    78  			ReopenKeywords                           []string
    79  			DefaultMergeStyle                        string
    80  			DefaultMergeMessageCommitsLimit          int
    81  			DefaultMergeMessageSize                  int
    82  			DefaultMergeMessageAllAuthors            bool
    83  			DefaultMergeMessageMaxApprovers          int
    84  			DefaultMergeMessageOfficialApproversOnly bool
    85  			PopulateSquashCommentWithCommitMessages  bool
    86  			AddCoCommitterTrailers                   bool
    87  		} `ini:"repository.pull-request"`
    88  
    89  		// Issue Setting
    90  		Issue struct {
    91  			LockReasons []string
    92  		} `ini:"repository.issue"`
    93  
    94  		Release struct {
    95  			AllowedTypes     string
    96  			DefaultPagingNum int
    97  		} `ini:"repository.release"`
    98  
    99  		Signing struct {
   100  			SigningKey        string
   101  			SigningName       string
   102  			SigningEmail      string
   103  			InitialCommit     []string
   104  			CRUDActions       []string `ini:"CRUD_ACTIONS"`
   105  			Merges            []string
   106  			Wiki              []string
   107  			DefaultTrustModel string
   108  		} `ini:"repository.signing"`
   109  	}{
   110  		DetectedCharsetsOrder: []string{
   111  			"UTF-8",
   112  			"UTF-16BE",
   113  			"UTF-16LE",
   114  			"UTF-32BE",
   115  			"UTF-32LE",
   116  			"ISO-8859-1",
   117  			"windows-1252",
   118  			"ISO-8859-2",
   119  			"windows-1250",
   120  			"ISO-8859-5",
   121  			"ISO-8859-6",
   122  			"ISO-8859-7",
   123  			"windows-1253",
   124  			"ISO-8859-8-I",
   125  			"windows-1255",
   126  			"ISO-8859-8",
   127  			"windows-1251",
   128  			"windows-1256",
   129  			"KOI8-R",
   130  			"ISO-8859-9",
   131  			"windows-1254",
   132  			"Shift_JIS",
   133  			"GB18030",
   134  			"EUC-JP",
   135  			"EUC-KR",
   136  			"Big5",
   137  			"ISO-2022-JP",
   138  			"ISO-2022-KR",
   139  			"ISO-2022-CN",
   140  			"IBM424_rtl",
   141  			"IBM424_ltr",
   142  			"IBM420_rtl",
   143  			"IBM420_ltr",
   144  		},
   145  		DetectedCharsetScore:                    map[string]int{},
   146  		AnsiCharset:                             "",
   147  		ForcePrivate:                            false,
   148  		DefaultPrivate:                          RepoCreatingLastUserVisibility,
   149  		DefaultPushCreatePrivate:                true,
   150  		MaxCreationLimit:                        -1,
   151  		PreferredLicenses:                       []string{"Apache License 2.0", "MIT License"},
   152  		DisableHTTPGit:                          false,
   153  		AccessControlAllowOrigin:                "",
   154  		UseCompatSSHURI:                         false,
   155  		DefaultCloseIssuesViaCommitsInAnyBranch: false,
   156  		EnablePushCreateUser:                    false,
   157  		EnablePushCreateOrg:                     false,
   158  		DisabledRepoUnits:                       []string{},
   159  		DefaultRepoUnits:                        []string{},
   160  		PrefixArchiveFiles:                      true,
   161  		DisableMigrations:                       false,
   162  		DisableStars:                            false,
   163  		DefaultBranch:                           "main",
   164  
   165  		// Repository editor settings
   166  		Editor: struct {
   167  			LineWrapExtensions   []string
   168  			PreviewableFileModes []string
   169  		}{
   170  			LineWrapExtensions:   strings.Split(".txt,.md,.markdown,.mdown,.mkd,", ","),
   171  			PreviewableFileModes: []string{"markdown"},
   172  		},
   173  
   174  		// Repository upload settings
   175  		Upload: struct {
   176  			Enabled      bool
   177  			TempPath     string
   178  			AllowedTypes string
   179  			FileMaxSize  int64
   180  			MaxFiles     int
   181  		}{
   182  			Enabled:      true,
   183  			TempPath:     "data/tmp/uploads",
   184  			AllowedTypes: "",
   185  			FileMaxSize:  3,
   186  			MaxFiles:     5,
   187  		},
   188  
   189  		// Repository local settings
   190  		Local: struct {
   191  			LocalCopyPath string
   192  		}{
   193  			LocalCopyPath: "tmp/local-repo",
   194  		},
   195  
   196  		// Pull request settings
   197  		PullRequest: struct {
   198  			WorkInProgressPrefixes                   []string
   199  			CloseKeywords                            []string
   200  			ReopenKeywords                           []string
   201  			DefaultMergeStyle                        string
   202  			DefaultMergeMessageCommitsLimit          int
   203  			DefaultMergeMessageSize                  int
   204  			DefaultMergeMessageAllAuthors            bool
   205  			DefaultMergeMessageMaxApprovers          int
   206  			DefaultMergeMessageOfficialApproversOnly bool
   207  			PopulateSquashCommentWithCommitMessages  bool
   208  			AddCoCommitterTrailers                   bool
   209  		}{
   210  			WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
   211  			// Same as GitHub. See
   212  			// https://help.github.com/articles/closing-issues-via-commit-messages
   213  			CloseKeywords:                            strings.Split("close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved", ","),
   214  			ReopenKeywords:                           strings.Split("reopen,reopens,reopened", ","),
   215  			DefaultMergeStyle:                        "merge",
   216  			DefaultMergeMessageCommitsLimit:          50,
   217  			DefaultMergeMessageSize:                  5 * 1024,
   218  			DefaultMergeMessageAllAuthors:            false,
   219  			DefaultMergeMessageMaxApprovers:          10,
   220  			DefaultMergeMessageOfficialApproversOnly: true,
   221  			PopulateSquashCommentWithCommitMessages:  false,
   222  			AddCoCommitterTrailers:                   true,
   223  		},
   224  
   225  		// Issue settings
   226  		Issue: struct {
   227  			LockReasons []string
   228  		}{
   229  			LockReasons: strings.Split("Too heated,Off-topic,Spam,Resolved", ","),
   230  		},
   231  
   232  		Release: struct {
   233  			AllowedTypes     string
   234  			DefaultPagingNum int
   235  		}{
   236  			AllowedTypes:     "",
   237  			DefaultPagingNum: 10,
   238  		},
   239  
   240  		// Signing settings
   241  		Signing: struct {
   242  			SigningKey        string
   243  			SigningName       string
   244  			SigningEmail      string
   245  			InitialCommit     []string
   246  			CRUDActions       []string `ini:"CRUD_ACTIONS"`
   247  			Merges            []string
   248  			Wiki              []string
   249  			DefaultTrustModel string
   250  		}{
   251  			SigningKey:        "default",
   252  			SigningName:       "",
   253  			SigningEmail:      "",
   254  			InitialCommit:     []string{"always"},
   255  			CRUDActions:       []string{"pubkey", "twofa", "parentsigned"},
   256  			Merges:            []string{"pubkey", "twofa", "basesigned", "commitssigned"},
   257  			Wiki:              []string{"never"},
   258  			DefaultTrustModel: "collaborator",
   259  		},
   260  	}
   261  	RepoRootPath string
   262  	ScriptType   = "bash"
   263  
   264  	RepoArchive = struct {
   265  		Storage
   266  	}{}
   267  )
   268  
   269  func newRepository() {
   270  	var err error
   271  	// Determine and create root git repository path.
   272  	sec := Cfg.Section("repository")
   273  	Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool()
   274  	Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool()
   275  	Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1)
   276  	Repository.DefaultBranch = sec.Key("DEFAULT_BRANCH").MustString(Repository.DefaultBranch)
   277  	RepoRootPath = sec.Key("ROOT").MustString(path.Join(AppDataPath, "gitbundle-repositories"))
   278  	forcePathSeparator(RepoRootPath)
   279  	if !filepath.IsAbs(RepoRootPath) {
   280  		RepoRootPath = filepath.Join(AppWorkPath, RepoRootPath)
   281  	} else {
   282  		RepoRootPath = filepath.Clean(RepoRootPath)
   283  	}
   284  	defaultDetectedCharsetsOrder := make([]string, 0, len(Repository.DetectedCharsetsOrder))
   285  	for _, charset := range Repository.DetectedCharsetsOrder {
   286  		defaultDetectedCharsetsOrder = append(defaultDetectedCharsetsOrder, strings.ToLower(strings.TrimSpace(charset)))
   287  	}
   288  	ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash")
   289  
   290  	if _, err := exec.LookPath(ScriptType); err != nil {
   291  		log.Warn("SCRIPT_TYPE %q is not on the current PATH. Are you sure that this is the correct SCRIPT_TYPE?", ScriptType)
   292  	}
   293  
   294  	if err = Cfg.Section("repository").MapTo(&Repository); err != nil {
   295  		log.Fatal("Failed to map Repository settings: %v", err)
   296  	} else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil {
   297  		log.Fatal("Failed to map Repository.Editor settings: %v", err)
   298  	} else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil {
   299  		log.Fatal("Failed to map Repository.Upload settings: %v", err)
   300  	} else if err = Cfg.Section("repository.local").MapTo(&Repository.Local); err != nil {
   301  		log.Fatal("Failed to map Repository.Local settings: %v", err)
   302  	} else if err = Cfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil {
   303  		log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
   304  	}
   305  
   306  	if !Cfg.Section("packages").Key("ENABLED").MustBool(true) {
   307  		Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages")
   308  	}
   309  
   310  	// Handle default trustmodel settings
   311  	Repository.Signing.DefaultTrustModel = strings.ToLower(strings.TrimSpace(Repository.Signing.DefaultTrustModel))
   312  	if Repository.Signing.DefaultTrustModel == "default" {
   313  		Repository.Signing.DefaultTrustModel = "collaborator"
   314  	}
   315  
   316  	// Handle preferred charset orders
   317  	preferred := make([]string, 0, len(Repository.DetectedCharsetsOrder))
   318  	for _, charset := range Repository.DetectedCharsetsOrder {
   319  		canonicalCharset := strings.ToLower(strings.TrimSpace(charset))
   320  		preferred = append(preferred, canonicalCharset)
   321  		// remove it from the defaults
   322  		for i, charset := range defaultDetectedCharsetsOrder {
   323  			if charset == canonicalCharset {
   324  				defaultDetectedCharsetsOrder = append(defaultDetectedCharsetsOrder[:i], defaultDetectedCharsetsOrder[i+1:]...)
   325  				break
   326  			}
   327  		}
   328  	}
   329  
   330  	i := 0
   331  	for _, charset := range preferred {
   332  		// Add the defaults
   333  		if charset == "defaults" {
   334  			for _, charset := range defaultDetectedCharsetsOrder {
   335  				canonicalCharset := strings.ToLower(strings.TrimSpace(charset))
   336  				if _, has := Repository.DetectedCharsetScore[canonicalCharset]; !has {
   337  					Repository.DetectedCharsetScore[canonicalCharset] = i
   338  					i++
   339  				}
   340  			}
   341  			continue
   342  		}
   343  		if _, has := Repository.DetectedCharsetScore[charset]; !has {
   344  			Repository.DetectedCharsetScore[charset] = i
   345  			i++
   346  		}
   347  	}
   348  
   349  	if !filepath.IsAbs(Repository.Upload.TempPath) {
   350  		Repository.Upload.TempPath = path.Join(AppWorkPath, Repository.Upload.TempPath)
   351  	}
   352  
   353  	RepoArchive.Storage = getStorage("repo-archive", "", nil)
   354  }