~imperator/quartiermeister-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
3

[PATCH 0/3] *** Proj Tree Printing v2 ***

Details
Message ID
<20210314091518.8391-1-stanner@posteo.de>
DKIM signature
missing
Download raw message
*** BLURB HERE ***

Hola,
Implemented most of your requösts and additionally removed type tags
from the remaining names (Ich think).

Philipp Stanner (3):
  qm: improve user informing
  lib: implement search methods and project creation
  bin: list: First version of project tree printing

 bin/qm-list/main.go | 118 ++++++++++++++++++++++++++++++++++++++------
 lib/collection.go   |  96 +++++++++++++++++++++++++++++++----
 lib/container.go    |  20 ++++----
 lib/project.go      |   5 +-
 qm                  |   3 +-
 5 files changed, 204 insertions(+), 38 deletions(-)

-- 
2.30.1

[PATCH 1/3] qm: improve user informing

Details
Message ID
<20210314091518.8391-2-stanner@posteo.de>
In-Reply-To
<20210314091518.8391-1-stanner@posteo.de> (view parent)
DKIM signature
missing
Download raw message
Patch: +2 -1
---
 qm | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/qm b/qm
index a3b2d6f..01362b5 100755
--- a/qm
+++ b/qm
@@ -16,10 +16,11 @@ main() {
    export QM_EDITOR="nvim"

    if [[ ! -d "$QM_PATH" ]]; then
        echo "\"$QM_PATH\" created."
        echo "No QM database yet. Initializing..."
        mkdir -p "$QM_PATH"
        mkdir -p "$QM_PATH"/$QM_COLLECTION/pool
        mkdir -p "$QM_PATH"/$QM_COLLECTION/projects
        echo "\"$QM_PATH\" initialized."
    fi

    if which "qm-$cmd" >& /dev/null; then
-- 
2.30.1

[PATCH 2/3] lib: implement search methods and project creation

Details
Message ID
<20210314091518.8391-3-stanner@posteo.de>
In-Reply-To
<20210314091518.8391-1-stanner@posteo.de> (view parent)
DKIM signature
missing
Download raw message
Patch: +98 -23
Implements:
- Projects are now created on collections.
- Layer-Search-Methods for tree-printing of projects
- UUIDs for projects
---
 lib/collection.go | 96 ++++++++++++++++++++++++++++++++++++++++++-----
 lib/container.go  | 20 +++++-----
 lib/project.go    |  5 +--
 3 files changed, 98 insertions(+), 23 deletions(-)

diff --git a/lib/collection.go b/lib/collection.go
index 37784ff..c0bc246 100644
--- a/lib/collection.go
+++ b/lib/collection.go
@@ -23,6 +23,11 @@ const (
	SearchAttrTag     = "tag"
)

type ProjectSubTree struct {
	Proj     *Project
	Subprojs []*ProjectSubTree
}

type Collection struct {
	Path         string
	PoolPath     string
@@ -99,9 +104,12 @@ func getProjMeta(path string) (*Project, error) {
	return proj, nil
}

// TODO: Works only properly with minimum number = 1. Maybe 0 is better?
func buildLayerNGlob(depth uint) string {
	var i uint
	s := "/"
	var (
		i uint
		s = "/"
	)

	for i = 0; i < depth; i++ {
		s += "*/"
@@ -112,26 +120,91 @@ func buildLayerNGlob(depth uint) string {
}

// get subprojects N layers deep
func (p *Project) GetSubprojectsN(depth uint) ([]*Project, error) {
	var subprojs []*Project
func (p *Project) GetSubprojectsN(depth int) ([]*Project, error) {
	var (
		subprojs []*Project
		glob = p.Path + buildLayerNGlob(uint(depth))
		matches, err = filepath.Glob(glob)
	)
	if err != nil {
		return nil, err
	}

	for _, m := range matches {
		foundP, err := getProjMeta(m)
		if err != nil {
			return nil, err
		}

		if foundP.UUID != p.UUID {
			subprojs = append(subprojs, foundP)
		}
	}

	return subprojs, nil
}

// calls itself recursively until all subprojects have been found.
func (p *Project) GetSubprojectTree() ([]*ProjectSubTree, error) {
	subprojs, err := p.GetSubprojectsN(1)
	if len(subprojs) == 0 || err != nil {
		return nil, err
	}

	glob := p.Path + buildLayerNGlob(depth)
	fmt.Println("glob: ", glob)
	var subtree []*ProjectSubTree

	for _, subpr := range subprojs {
		deeperSubs, err := subpr.GetSubprojectTree()
		if err != nil {
			break
		}
		filler := ProjectSubTree{Proj: subpr, Subprojs: deeperSubs}
		subtree = append(subtree, &filler)
	}

	return subtree, err
}

// TODO implement this
func (c *Collection) GetProjectTree() ([]ProjectSubTree, error) {
	var tree []ProjectSubTree

	_, err := c.AllProjects()
	if err != nil {
		return nil, err
	}

	return tree, nil
}

// Gets all Projects layer N deep. Can be used to get all root projects.
func (c *Collection) AllProjectsN(depth int) ([]*Project, error) {
	var (
		projs []*Project
		err   error
	)
	if depth == 0 {
		return nil, fmt.Errorf("Invalid depth")
	} else if depth == -1 {
		return c.AllProjects()
	}

	glob := c.ProjectsPath + buildLayerNGlob(uint(depth))
	matches, err := filepath.Glob(glob)
	if err != nil {
		return nil, err
	}
	fmt.Println("nr of matches: ", len(matches))

	for _, m := range matches {
		p, err := getProjMeta(m)
		foundP, err := getProjMeta(m)
		if err != nil {
			return nil, err
		}
		subprojs = append(subprojs, p)

		projs = append(projs, foundP)
	}

	return subprojs, nil
	return projs, nil
}

func (c *Collection) AllProjects() ([]*Project, error) {
@@ -140,6 +213,7 @@ func (c *Collection) AllProjects() ([]*Project, error) {
		err   error
	)

	// FIXME: Chdir sucks
	if err = os.Chdir(c.ProjectsPath); err != nil {
		return nil, err
	}
@@ -208,6 +282,8 @@ func (p *Collection) FindTags(t *Item) ([]*Tag, error) {
	return out, nil
}

// TODO: warn user when there is more than 1 proj with identical name
// if there is, than make him choose by UUID.
func (c *Collection) ProjectByTitle(title string) (*Project, error) {
	// TODO: implement this more efficently
	projs, err := c.AllProjects()
diff --git a/lib/container.go b/lib/container.go
index 5859a42..7a32365 100644
--- a/lib/container.go
+++ b/lib/container.go
@@ -7,6 +7,7 @@ package qm

import (
	"encoding/json"
	"github.com/google/uuid"
	"os"
	"path/filepath"
	"time"
@@ -18,26 +19,24 @@ type Container struct {
	Description string    `json:"description" yaml:"description"`
	CreatedAt   time.Time `json:"created_at" yaml:"created_at"`
	Path        string    `json:"path" yaml:"-"`
	UUID        uuid.UUID `json:"uuid" yaml:"uuid"`
	parent      string
}

func checkParentExists(c *Collection, title string) error {
	_, err := c.ProjectByTitle(title)
	return err
}

// FIXME: this should not only work for Projects
func (c *Collection) CreateContainer(title,
		descr, type_, parent string) (*Container, error) {
		descr, type_, parentTitle string) (*Container, error) {
	var path string
	slug := Slug(title)

	if parent == "" {
	if parentTitle == "" {
		path = filepath.Join(c.Path, type_, slug)
	} else {
		if err := checkParentExists(c, parent); err != nil {
		parent, err := c.ProjectByTitle(parentTitle)
		if err != nil {
			return nil, err
		}
		path = filepath.Join(c.Path, type_, parent, slug)
		path = filepath.Join(parent.Path, slug)
	}

	cont := &Container{
@@ -46,7 +45,8 @@ func (c *Collection) CreateContainer(title,
		Description: descr,
		CreatedAt:   time.Now(),
		Path:        path,
		parent:      parent,
		UUID:        uuid.New(),
		parent:      parentTitle,
	}

	return cont, nil
diff --git a/lib/project.go b/lib/project.go
index 946b3d0..51b33f1 100644
--- a/lib/project.go
+++ b/lib/project.go
@@ -19,10 +19,9 @@ type Project struct {
	//Progress uint `json:"progress" yaml:"progress"`
}

func (c *Collection) CreateProject(title, description,
		parent string) (*Project, error) {
func (c *Collection) CreateProject(title, descr, parent string) (*Project, error) {
	p := &Project{}
	cont, err := c.CreateContainer(title, description, "projects", parent)
	cont, err := c.CreateContainer(title, descr, "projects", parent)
	if err != nil {
		return nil, err
	}
-- 
2.30.1

[PATCH 3/3] bin: list: First version of project tree printing

Details
Message ID
<20210314091518.8391-4-stanner@posteo.de>
In-Reply-To
<20210314091518.8391-1-stanner@posteo.de> (view parent)
DKIM signature
missing
Download raw message
Patch: +104 -14
Working, but incomplete first draft of proj-tree printing.
---
 bin/qm-list/main.go | 118 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 104 insertions(+), 14 deletions(-)

diff --git a/bin/qm-list/main.go b/bin/qm-list/main.go
index 512baca..b22e532 100644
--- a/bin/qm-list/main.go
@@ -2,51 +2,141 @@ package main

import (
	"fmt"
	"os"

	qm "git.sr.ht/~imperator/quartiermeister/lib"
	"github.com/integrii/flaggy"
)

func listItems(c *qm.Collection) {
type options struct {
	recurse uint
	noLines bool
}

// options should be global, otherwise get passed around 1000 times.
var opts options

func listItems(c *qm.Collection) error {
	items, err := c.AllItems()
	if err != nil {
		fmt.Println("error: ", err)
		return
		return err
	}
	for _, i := range items {
		fmt.Println(i.Title)
	}

	return nil
}

// creates string prefix for printing a tree
func prefixByDepth(depth int) string {
	var (
		indentation string
		prefix = "├─"
		lengthener = "────"
	)

	if depth == 0 {
		return ""
	}

	if opts.noLines {
		prefix = "  "
		lengthener = "    "
	}

	for i := 0; i < depth; i++ {
		indentation += lengthener
	}
	prefix += indentation

	return prefix
}

func decrDepth(depth *int) {
	*depth -= 1
}

// prints passed subproject and all its subprojects recursively
func printProjAndSubs(subproj *qm.ProjectSubTree, depth int) error {
	defer decrDepth(&depth)

	// when this function recurses, the recursors get higher and higher
	// numbers, causing the right indentation.
	prefix := prefixByDepth(depth)
	depth += 1

	// TODO: find out why there is a whitespace too much
	fmt.Println(prefix, subproj.Proj.Title)

	for _, proj := range subproj.Subprojs {
		prefix = prefixByDepth(depth)
		fmt.Println(prefix, proj.Proj.Title)
		subprojs, err := proj.Proj.GetSubprojectTree()
		if err != nil {
			return err
		}

		for _, sub := range subprojs {
			depth += 1 // ugly... recursion.
			printProjAndSubs(sub, depth)
			depth -= 1
		}
	}

	return nil
}

func listProjs(c *qm.Collection) {
	projs, err := c.AllProjects()
// loads all projects and passes them to the print function
func printProjFamily(c *qm.Collection) error {
	projs, err := c.AllProjectsN(1)
	if err != nil {
		fmt.Println("error: ", err)
		return
		return err
	}
	for _, p := range projs {
		fmt.Println(p.Title)
	}
	for _, proj := range projs {
		tmpSubs, err := proj.GetSubprojectTree()
		if err != nil {
			return err
		}

		tmp := qm.ProjectSubTree{proj, tmpSubs}
		if err = printProjAndSubs(&tmp, 0); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	var (
		itemCmd = flaggy.NewSubcommand("items")
		projCmd = flaggy.NewSubcommand("projs")
	)
	var err error
	itemCmd := flaggy.NewSubcommand("items")
	projCmd := flaggy.NewSubcommand("projs")
	projCmd.UInt(&opts.recurse, "r", "recurse",
		"<N> show subprojects N layers deep")
	flaggy.Bool(&opts.noLines, "n", "no-lines", "Show no lines")

	flaggy.AttachSubcommand(itemCmd, 1)
	flaggy.AttachSubcommand(projCmd, 1)
	flaggy.Parse()

	c, err := qm.LoadCollection()
	if err != nil {
		fmt.Println("error: ", err)
		fmt.Fprintln(os.Stderr, "error: ", err)
		return
	}

	if itemCmd.Used {
		listItems(c)
		err = listItems(c)
	} else if projCmd.Used {
		listProjs(c)
		err = printProjFamily(c)
	}

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
-- 
2.30.1
Reply to thread Export thread (mbox)