diff options
Diffstat (limited to 'spdxconv.go')
| -rw-r--r-- | spdxconv.go | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/spdxconv.go b/spdxconv.go new file mode 100644 index 0000000..5f28e5a --- /dev/null +++ b/spdxconv.go @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2025 M. Shulhan <ms@kilabit.info> + +package spdxconv + +import ( + "fmt" + "os" + "path/filepath" + + "git.sr.ht/~shulhan/pakakeh.go/lib/git" + "git.sr.ht/~shulhan/pakakeh.go/lib/ini" +) + +// SPDXConv the main type for converting files to SPDX format. +type SPDXConv struct { + scm sourceCodeManagement + + // dir define the directory that will processed. + // `name` is single file inside `dir` to be processed. + // If `name` is empty means process all files inside `dir`. + dir string + name string + + // scmDir define the root directory for source-code management. + // In git, the path that contains the ".git" directory. + scmDir string + + cfg config +} + +// Apply the SPDX license headers to all files inside the directory `path` or +// to single file only. +func Apply(path string) (err error) { + var logp = `Apply` + var conv *SPDXConv + + conv, err = New(path) + if err != nil { + return fmt.Errorf(`%s: %w`, logp, err) + } + var listFile []string + if conv.name == `` { + listFile, err = conv.scanFiles([]string{conv.dir}) + } else { + listFile, err = conv.scanFile(conv.dir, conv.name) + } + if err != nil { + return fmt.Errorf(`%s: %w`, logp, err) + } + + var pathFile string + for _, pathFile = range listFile { + conv.convert(pathFile) + } + return nil +} + +// New initialize new instance of SPDXConv +func New(path string) (conv *SPDXConv, err error) { + var logp = `New` + + path, err = filepath.Abs(path) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + conv = &SPDXConv{} + var fi os.FileInfo + fi, err = os.Stat(path) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + if fi.IsDir() { + conv.dir = path + } else { + conv.dir, conv.name = filepath.Split(path) + } + + err = conv.loadConfig(conv.dir) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + err = conv.scanForSCM(conv.dir) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + return conv, nil +} + +// loadConfig load the program configuration from file `spdxconv.cfg` in the +// current directory. +func (conv *SPDXConv) loadConfig(dir string) (err error) { + var logp = `loadConfig` + var pathcfg = filepath.Join(dir, `spdxconv.cfg`) + var rawcfg []byte + rawcfg, err = os.ReadFile(pathcfg) + if err != nil { + if os.IsNotExist(err) { + return nil + } + return fmt.Errorf(`%s %s: %w`, logp, pathcfg, err) + } + err = ini.Unmarshal(rawcfg, &conv.cfg) + if err != nil { + return fmt.Errorf(`%s %s: %w`, logp, pathcfg, err) + } + err = conv.cfg.init() + if err != nil { + return fmt.Errorf(`%s %s: %w`, logp, pathcfg, err) + } + return nil +} + +// scanForSCM scan for source-code management (SCM) from directory `dir` up +// until the root. +// Currently, only support git. +func (conv *SPDXConv) scanForSCM(dir string) (err error) { + var scmDir string + var fi os.FileInfo + for dir != `/` { + scmDir = filepath.Join(dir, `.git`) + fi, err = os.Stat(scmDir) + if err != nil { + if os.IsNotExist(err) { + continue + } + return err + } + if !fi.IsDir() { + continue + } + conv.scmDir = dir + conv.scm, err = git.New(dir) + if err != nil { + return err + } + return nil + } + conv.scm = &dummySCM{} + return nil +} + +// scanFile check if the single file can be processed or not. +func (conv *SPDXConv) scanFile(dir, name string) (listFile []string, err error) { + var pathName = filepath.Join(dir, name) + if conv.scm.IsIgnored(pathName) { + return nil, nil + } + listFile = append(listFile, pathName) + return listFile, nil +} + +// scanFiles list file to be processed in directory `dir`, recursively. +// A file ignored by ".gitignore" file will be excluded. +// A common ignore file or directory name likes ".git", "node_modules", and +// "vendor"; also will be excluded. +func (conv *SPDXConv) scanFiles(listDir []string) (listFile []string, err error) { + var commonIgnore = map[string]struct{}{ + `.git`: struct{}{}, + `node_modules`: struct{}{}, + `vendor`: struct{}{}, + } + var dir string + var listde []os.DirEntry + var de os.DirEntry + var ok bool + for len(listDir) != 0 { + dir = listDir[0] + listDir = listDir[1:] + + listde, err = os.ReadDir(dir) + if err != nil { + return listFile, err + } + for _, de = range listde { + var name = de.Name() + if conv.scm.IsIgnored(name) { + continue + } + _, ok = commonIgnore[name] + if ok { + continue + } + var pathName = filepath.Join(dir, name) + if de.IsDir() { + listDir = append(listDir, pathName) + continue + } + listFile = append(listFile, pathName) + } + } + return listFile, nil +} + +// convert the given pathFile to SPDX license format. +func (conv *SPDXConv) convert(pathFile string) { + +} |
