summaryrefslogtreecommitdiffstats
path: root/fs/fs-writeback.c
AgeCommit message (Expand)Author
2017-10-10writeback: merge try_to_writeback_inodes_sb_nr() into callerRakesh Pandit
2017-10-04writeback: eliminate work item allocation in bd_start_writeback()Jens Axboe
2017-10-03writeback: only allow one inflight and pending full flushJens Axboe
2017-10-03writeback: move nr_pages == 0 logic to one locationJens Axboe
2017-10-03writeback: make wb_start_writeback() staticJens Axboe
2017-10-03writeback: provide a wakeup_flusher_threads_bdi()Jens Axboe
2017-10-03writeback: remove 'range_cyclic' argument for wb_start_writeback()Jens Axboe
2017-10-03writeback: switch wakeup_flusher_threads() to cyclic writebackJens Axboe
2017-10-03fs: kill 'nr_pages' argument from wakeup_flusher_threads()Jens Axboe
2017-07-12writeback: rework wb_[dec|inc]_stat family of functionsNikolay Borisov
2017-05-16fs: add a blank lines on some kernel-doc commentsMauro Carvalho Chehab
2017-03-13writeback: fix memory leak in wb_queue_work()Tahsin Erdogan
2016-12-12fs/fs-writeback.c: remove redundant if checkTahsin Erdogan
2016-08-09mm, writeback: flush plugged IO in wakeup_flusher_threads()Konstantin Khlebnikov
2016-08-04writeback: Write dirty times for WB_SYNC_ALL writebackJan Kara
2016-07-28mm: move most file-based accounting to the nodeMel Gorman
2016-07-26fs/fs-writeback.c: inode writeback list tracking tracepointsBrian Foster
2016-07-26fs/fs-writeback.c: add a new writeback list for syncDave Chinner
2016-06-30writeback: inode cgroup wb switch should not call ihold()Tahsin Erdogan
2016-05-20mm,writeback: don't use memory reserves for wb_start_writebackTetsuo Handa
2016-04-04mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macrosKirill A. Shutemov
2016-03-20writeback, cgroup: fix use of the wrong bdi_writeback which mismatches the inodeTejun Heo
2016-03-20writeback, cgroup: fix premature wb_put() in locked_inode_to_wb_and_lock_list()Tejun Heo
2016-03-03writeback: flush inode cgroup wb switches instead of pinning super_blockTejun Heo
2016-02-16writeback: keep superblock pinned during cgroup writeback association switchesTejun Heo
2016-01-15cgroup, memcg, writeback: drop spurious rcu locking around mem_cgroup_css_fro...Tejun Heo
2015-11-09fs/writeback.c: fix kernel-doc warningsRandy Dunlap
2015-11-05mm/filemap.c: make global sync not clear error status of individual inodesJunichi Nomura
2015-10-28fs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_s...Tejun Heo
2015-10-12writeback: bdi_writeback iteration must not skip dying onesTejun Heo
2015-10-12writeback: fix bdi_writeback iteration in wakeup_dirtytime_writeback()Tejun Heo
2015-09-19fs-writeback: unplug before cond_resched in writeback_sb_inodesChris Mason
2015-09-12writeback: plug writeback in wb_writeback() and writeback_inodes_wb()Linus Torvalds
2015-09-11Revert "writeback: plug writeback at a high level"Linus Torvalds
2015-09-10Merge branch 'for-4.3/blkcg' of git://git.kernel.dk/linux-blockLinus Torvalds
2015-09-05Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/vir...Linus Torvalds
2015-08-25writeback: sync_inodes_sb() must write out I_DIRTY_TIME inodes and always cal...Tejun Heo
2015-08-18writeback: update writeback tracepoints to report cgroupTejun Heo
2015-08-18writeback: explain why @inode is allowed to be NULL for inode_congested()Tejun Heo
2015-08-18writeback: remove wb_writeback_work->single_wait/doneTejun Heo
2015-08-18writeback: bdi_for_each_wb() iteration is memcg ID based not blkcgTejun Heo
2015-08-17inode: rename i_wb_list to i_io_listDave Chinner
2015-08-17sync: serialise per-superblock sync operationsDave Chinner
2015-08-17inode: convert inode_sb_list_lock to per-sbDave Chinner
2015-08-17writeback: plug writeback at a high levelDave Chinner
2015-07-23block: export bio_associate_*() and wbc_account_io()Tejun Heo
2015-06-17writeback: do foreign inode detection iff cgroup writeback is enabledTejun Heo
2015-06-02writeback: disassociate inodes from dying bdi_writebacksTejun Heo
2015-06-02writeback: implement foreign cgroup inode bdi_writeback switchingTejun Heo
2015-06-02writeback: add lockdep annotation to inode_to_wb()Tejun Heo
17'>117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
// Copyright 2019 The Hugo Authors. All rights reserved.
//
// Licensed 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 navigation

import (
	"github.com/gohugoio/hugo/common/maps"
	"github.com/gohugoio/hugo/common/types"

	"github.com/pkg/errors"
	"github.com/spf13/cast"
)

type PageMenusProvider interface {
	PageMenusGetter
	MenuQueryProvider
}

type PageMenusGetter interface {
	Menus() PageMenus
}

type MenusGetter interface {
	Menus() Menus
}

type MenuQueryProvider interface {
	HasMenuCurrent(menuID string, me *MenuEntry) bool
	IsMenuCurrent(menuID string, inme *MenuEntry) bool
}

func PageMenusFromPage(p Page) (PageMenus, error) {
	params := p.Params()

	ms, ok := params["menus"]
	if !ok {
		ms, ok = params["menu"]
	}

	pm := PageMenus{}

	if !ok {
		return nil, nil
	}

	me := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight()}

	// Could be the name of the menu to attach it to
	mname, err := cast.ToStringE(ms)

	if err == nil {
		me.Menu = mname
		pm[mname] = &me
		return pm, nil
	}

	// Could be a slice of strings
	mnames, err := cast.ToStringSliceE(ms)

	if err == nil {
		for _, mname := range mnames {
			me.Menu = mname
			pm[mname] = &me
		}
		return pm, nil
	}

	var wrapErr = func(err error) error {
		return errors.Wrapf(err, "unable to process menus for page %q", p.Path())
	}

	// Could be a structured menu entry
	menus, err := maps.ToStringMapE(ms)
	if err != nil {
		return pm, wrapErr(err)
	}

	for name, menu := range menus {
		menuEntry := MenuEntry{Page: p, Name: p.LinkTitle(), Weight: p.Weight(), Menu: name}
		if menu != nil {
			ime, err := maps.ToStringMapE(menu)
			if err != nil {
				return pm, wrapErr(err)
			}

			if err = menuEntry.MarshallMap(ime); err != nil {
				return pm, wrapErr(err)
			}
		}
		pm[name] = &menuEntry
	}

	return pm, nil
}

func NewMenuQueryProvider(
	pagem PageMenusGetter,
	sitem MenusGetter,
	p Page) MenuQueryProvider {
	return &pageMenus{
		p:     p,
		pagem: pagem,
		sitem: sitem,
	}
}

type pageMenus struct {
	pagem PageMenusGetter
	sitem MenusGetter
	p     Page
}

func (pm *pageMenus) HasMenuCurrent(menuID string, me *MenuEntry) bool {
	if !types.IsNil(me.Page) && me.Page.IsSection() {
		if ok, _ := me.Page.IsAncestor(pm.p); ok {
			return true
		}
	}

	if !me.HasChildren() {
		return false
	}

	menus := pm.pagem.Menus()

	if m, ok := menus[menuID]; ok {
		for _, child := range me.Children {
			if child.IsEqual(m) {
				return true
			}
			if pm.HasMenuCurrent(menuID, child) {
				return true
			}
		}
	}

	if pm.p == nil {
		return false
	}

	for _, child := range me.Children {
		if child.isSamePage(pm.p) {
			return true
		}

		if pm.HasMenuCurrent(menuID, child) {
			return true
		}
	}

	return false
}

func (pm *pageMenus) IsMenuCurrent(menuID string, inme *MenuEntry) bool {
	menus := pm.pagem.Menus()

	if me, ok := menus[menuID]; ok {
		if me.IsEqual(inme) {
			return true
		}
	}

	if pm.p == nil {
		return false
	}

	if !inme.isSamePage(pm.p) {
		return false
	}

	// This resource may be included in several menus.
	// Search for it to make sure that it is in the menu with the given menuId.
	if menu, ok := pm.sitem.Menus()[menuID]; ok {
		for _, menuEntry := range menu {
			if menuEntry.IsSameResource(inme) {
				return true
			}

			descendantFound := pm.isSameAsDescendantMenu(inme, menuEntry)
			if descendantFound {
				return descendantFound
			}

		}
	}

	return false
}

func (pm *pageMenus) isSameAsDescendantMenu(inme *MenuEntry, parent *MenuEntry) bool {
	if parent.HasChildren() {
		for _, child := range parent.Children {
			if child.IsSameResource(inme) {
				return true
			}
			descendantFound := pm.isSameAsDescendantMenu(inme, child)
			if descendantFound {
				return descendantFound
			}
		}
	}
	return false
}

var NopPageMenus = new(nopPageMenus)

type nopPageMenus int

func (m nopPageMenus) Menus() PageMenus {
	return PageMenus{}
}

func (m nopPageMenus) HasMenuCurrent(menuID string, me *MenuEntry) bool {
	return false
}

func (m nopPageMenus) IsMenuCurrent(menuID string, inme *MenuEntry) bool {
	return false
}