mozilla profile manager: handle profiles for many flavours

This commit is contained in:
blob42 2023-09-19 19:32:55 +02:00
parent 59eb4b8f5c
commit ac70d2e3a7
14 changed files with 330 additions and 315 deletions

View File

@ -29,26 +29,26 @@ import (
"git.blob42.xyz/gosuki/gosuki/cmd"
"git.blob42.xyz/gosuki/gosuki/internal/logging"
"git.blob42.xyz/gosuki/gosuki/pkg/browsers/mozilla"
"git.blob42.xyz/gosuki/gosuki/internal/utils"
"github.com/urfave/cli/v2"
)
var fflog = logging.GetLogger("FF")
var ffUnlockVFSCmd = cli.Command{
var (
ffUnlockVFSCmd = cli.Command{
Name: "unlock",
Aliases: []string{"u"},
Action: ffUnlockVFS,
}
}
var ffCheckVFSCmd = cli.Command{
ffCheckVFSCmd = cli.Command{
Name: "check",
Aliases: []string{"c"},
Action: ffCheckVFS,
}
}
var ffVFSCommands = cli.Command{
ffVFSCommands = cli.Command{
Name: "vfs",
Usage: "VFS locking commands",
Subcommands: []*cli.Command{
@ -57,20 +57,21 @@ var ffVFSCommands = cli.Command{
},
}
var ffListProfilesCmd = cli.Command{
ffListProfilesCmd = cli.Command{
Name: "list",
Aliases: []string{"l"},
Action: ffListProfiles,
}
}
var ffProfilesCmds = cli.Command{
ffProfilesCmds = cli.Command{
Name: "profiles",
Aliases: []string{"p"},
Usage: "Profiles commands",
Subcommands: []*cli.Command{
&ffListProfilesCmd,
},
}
}
)
var FirefoxCmds = &cli.Command{
Name: "firefox",
@ -90,14 +91,21 @@ func init() {
//TODO: #54 define interface for modules to handle and list profiles
//FIX: Remove since profile listing is implemented at the main module level
func ffListProfiles(_ *cli.Context) error {
profs, err := FirefoxProfileManager.GetProfiles()
flavours := FirefoxProfileManager.ListFlavours()
for _, f := range flavours {
profs, err := FirefoxProfileManager.GetProfiles(f.Name)
if err != nil {
return err
}
for _, p := range profs {
fmt.Printf("%-10s \t %s\n", p.Name, utils.ExpandPath(FirefoxProfileManager.ConfigDir, p.Path))
if fullPath, err := p.AbsolutePath(); err != nil {
return err
} else {
fmt.Printf("%-10s \t %s\n", p.Name, fullPath)
}
}
}
return nil
}

View File

@ -24,27 +24,26 @@ package firefox
import (
"fmt"
"os"
"path/filepath"
"git.blob42.xyz/gosuki/gosuki/internal/config"
"git.blob42.xyz/gosuki/gosuki/internal/database"
"git.blob42.xyz/gosuki/gosuki/internal/utils"
"git.blob42.xyz/gosuki/gosuki/pkg/browsers/mozilla"
"git.blob42.xyz/gosuki/gosuki/pkg/modules"
"git.blob42.xyz/gosuki/gosuki/pkg/parsing"
"git.blob42.xyz/gosuki/gosuki/pkg/profiles"
"git.blob42.xyz/gosuki/gosuki/pkg/tree"
"github.com/fatih/structs"
"github.com/mitchellh/mapstructure"
"github.com/urfave/cli/v2"
)
const (
BrowserName = "firefox"
//TODO: auto detect firefox base dir based on OS and installed flavors
FirefoxBaseDir = "$HOME/.mozilla/firefox"
// FirefoxBaseDir = "$HOME/.mozilla/firefox"
DefaultProfile = "default"
// Default flavour to use
BrowserName = mozilla.FirefoxFlavour
)
var (
@ -52,15 +51,14 @@ var (
// firefox global config state.
FFConfig = NewFirefoxConfig()
ffProfileLoader = &mozilla.INIProfileLoader{
ffProfileLoader = &profiles.INIProfileLoader{
//BasePath to be set at runtime in init
ProfilesFile: mozilla.ProfilesFile,
}
FirefoxProfileManager = &mozilla.MozProfileManager{
BrowserName: BrowserName,
PathGetter: ffProfileLoader,
}
FirefoxProfileManager = mozilla.NewMozProfileManager(
ffProfileLoader,
)
)
// FirefoxConfig implements the Configurator interface
@ -86,27 +84,34 @@ type FirefoxConfig struct {
}
func setBookmarkDir(fc *FirefoxConfig) {
pm := FirefoxProfileManager
var err error
// pm := FirefoxProfileManager
// expand environment variables in path
pm.ConfigDir = filepath.Join(os.ExpandEnv(FirefoxBaseDir))
// pm.ConfigDir = filepath.Join(os.ExpandEnv(FirefoxBaseDir))
// Check if base folder exists
exists, err := utils.CheckDirExists(pm.ConfigDir)
if !exists {
log.Criticalf("the base firefox folder <%s> does not exist", pm.ConfigDir)
}
// handled by profiles.Detect()
// exists, err := utils.CheckDirExists(pm.ConfigDir)
// if !exists {
// log.Criticalf("the base firefox folder <%s> does not exist", pm.ConfigDir)
// }
if err != nil {
// if err != nil {
// log.Fatal(err)
// return
// }
// Set in NewMozProfileManager
// ffProfileLoader.BasePath = pm.ConfigDir
// load the default profile from the one defined in the config
var profile *profiles.Profile
if profile, err = FirefoxProfileManager.GetProfileByName(BrowserName, fc.Profile); err != nil {
log.Fatal(err)
return
}
// The next part prepares the default profile using the profile manager
ffProfileLoader.BasePath = pm.ConfigDir
// use default profile
// WIP: calling multiple profiles uses the following logic
bookmarkDir, err := FirefoxProfileManager.GetProfilePath(fc.Profile)
bookmarkDir, err := profile.AbsolutePath()
if err != nil {
log.Fatal(err)
}
@ -185,51 +190,6 @@ func (fc *FirefoxConfig) MapFrom(src interface{}) error {
return mapstructure.Decode(src, fc)
}
//REFACT:
// Hook called when the config is ready
func initFirefoxConfig(c *cli.Context) error {
log.Debugf("<firefox> initializing config")
// The following code is executed before the cli context is ready
// so we cannot use cli flags here
pm := FirefoxProfileManager
// expand environment variables in path
pm.ConfigDir = filepath.Join(os.ExpandEnv(FirefoxBaseDir))
// Check if base folder exists
exists, err := utils.CheckDirExists(pm.ConfigDir)
if !exists {
log.Criticalf("the base firefox folder <%s> does not exist", pm.ConfigDir)
}
if err != nil {
log.Fatal(err)
return err
}
// The next part prepares the default profile using the profile manager
ffProfileLoader.BasePath = pm.ConfigDir
// use default profile
// WIP: calling multiple profiles uses the following logic
bookmarkDir, err := FirefoxProfileManager.GetProfilePath(FFConfig.Profile)
if err != nil {
log.Fatal(err)
}
// update bookmark dir in firefox config
//TEST: verify that bookmark dir is set before browser is started
FFConfig.BkDir = bookmarkDir
log.Debugf("Using profile %s", bookmarkDir)
return nil
}
func init() {
config.RegisterConfigurator(BrowserName, FFConfig)
// config.RegisterConfReadyHooks(initFirefoxConfig)
}

View File

@ -90,6 +90,11 @@ type Firefox struct {
}
func (firefox *Firefox) ListFlavours() []profiles.BrowserFlavour {
return FirefoxProfileManager.ListFlavours()
}
// func (ff *Firefox) updateModifiedFolders(since timestamp) ([]*MozFolder, error) {
// // Get list of modified folders
@ -265,16 +270,8 @@ func (f Firefox) fullId() string {
}
// Implements the profiles.ProfileManager interface
func (f *Firefox) GetProfiles() ([]*profiles.Profile, error) {
return FirefoxProfileManager.GetProfiles()
}
func (f *Firefox) GetDefaultProfile() (*profiles.Profile, error) {
return FirefoxProfileManager.GetDefaultProfile()
}
func (f *Firefox) GetProfilePath(p profiles.Profile) string {
return filepath.Join(FirefoxProfileManager.ConfigDir, p.Path)
func (f *Firefox) GetProfiles(flavour string) ([]*profiles.Profile, error) {
return FirefoxProfileManager.GetProfiles(flavour)
}
// If should watch all profiles
@ -288,13 +285,12 @@ func (f *Firefox) UseProfile(p profiles.Profile) error {
f.Profile = p.Name
// setup the bookmark dir
bookmarkDir, err := FirefoxProfileManager.GetProfilePath(p.Name)
if err != nil {
if bookmarkDir, err := p.AbsolutePath(); err != nil {
return err
}
} else {
f.BkDir = bookmarkDir
return nil
}
}
func (f *Firefox) cloneConfig() {
@ -312,19 +308,16 @@ func (f *Firefox) Init(ctx *modules.Context, p *profiles.Profile) error {
f.Profile = p.Name
bookmarkDir, err := FirefoxProfileManager.GetProfilePath(p.Name)
if err != nil {
if bookmarkDir, err := p.AbsolutePath(); err != nil {
return err
}
} else {
f.BkDir = bookmarkDir
}
return f.init(ctx)
}
// TEST:
// TODO: implement watching of multiple profiles.
// NOTE: should be done at core gosuki level where multiple instances are spawned for each profile
//
// Implements browser.Initializer interface
func (f *Firefox) init(ctx *modules.Context) error {
log.Infof("initializing <%s>", f.fullId())
@ -356,7 +349,6 @@ func (f *Firefox) init(ctx *modules.Context) error {
/*
*Run reducer to avoid duplicate jobs when a batch of events is received
*/
// TODO!: make a new copy of places for every new event change
// Add a reducer to the watcher
log.Debugf("Running reducer on path <%s>", watchedPath)
@ -748,6 +740,7 @@ func init() {
var _ modules.BrowserModule = (*Firefox)(nil)
var _ modules.ProfileInitializer = (*Firefox)(nil)
var _ profiles.ProfileManager = (*Firefox)(nil)
var _ modules.Loader = (*Firefox)(nil)
var _ modules.Shutdowner = (*Firefox)(nil)
var _ watch.WatchRunner = (*Firefox)(nil)

View File

@ -156,7 +156,9 @@ func startDaemon(c *cli.Context) error {
bpm, ok := browser.(profiles.ProfileManager)
if ok {
if bpm.WatchAllProfiles() {
profs, err := bpm.GetProfiles()
falvours := bpm.ListFlavours()
for _, f := range falvours {
profs, err := bpm.GetProfiles(f.Name)
if err != nil {
log.Critical("could not get profiles")
continue
@ -169,6 +171,7 @@ func startDaemon(c *cli.Context) error {
continue
}
}
}
} else {
log.Debugf("profile manager <%s> not watching all profiles",
browser.Config().Name)

View File

@ -38,7 +38,7 @@ import (
_ "git.blob42.xyz/gosuki/gosuki/browsers/firefox"
// Load chrome browser module
_ "git.blob42.xyz/gosuki/gosuki/browsers/chrome"
// _ "git.blob42.xyz/gosuki/gosuki/browsers/chrome"
)
var log = logging.GetLogger("")
@ -95,6 +95,9 @@ func main() {
// Execute config hooks
//TODO: better doc for what are Conf hooks ???
// modules can run custom code before the CLI is ready.
// For example read the environment and set configuration options to be
// used by the module instances.
config.RunConfHooks(c)
initConfig()

View File

@ -82,4 +82,3 @@ var listModulesCmd = &cli.Command{
return nil
},
}

View File

@ -22,11 +22,14 @@
package cmd
import (
"errors"
"fmt"
"github.com/urfave/cli/v2"
"git.blob42.xyz/gosuki/gosuki/internal/utils"
"git.blob42.xyz/gosuki/gosuki/pkg/modules"
"git.blob42.xyz/gosuki/gosuki/pkg/profiles"
"github.com/urfave/cli/v2"
)
@ -37,15 +40,15 @@ var ProfileCmds = &cli.Command{
Usage: "profile commands",
Subcommands: []*cli.Command{
listProfilesCmd,
detectInstalledCmd,
},
}
//TODO: only enable commands when modules which implement profiles interfaces
// are available
var listProfilesCmd = &cli.Command{
Name: "list",
Usage: "list available profiles",
Usage: "list all available profiles",
Action: func(c *cli.Context) error {
browsers := modules.GetBrowserModules()
@ -59,21 +62,65 @@ var listProfilesCmd = &cli.Command{
pm, isProfileManager := brmod.(profiles.ProfileManager)
if !isProfileManager{
log.Critical("not profile manager")
return errors.New("not profile manager")
}
if isProfileManager {
// handle default profile commands
profs, err := pm.GetProfiles()
flavours := pm.ListFlavours()
for _, f := range flavours {
fmt.Printf("Profiles for <%s> flavour <%s>:\n\n", br.ModInfo().ID, f.Name)
if profs, err := pm.GetProfiles(f.Name); err != nil {
return err
} else {
for _, p := range profs {
pPath, err := p.AbsolutePath()
if err != nil {
return err
}
for _, p := range profs {
fmt.Printf("%-10s \t %s\n", p.Name, pm.GetProfilePath(*p))
fmt.Printf("%-10s \t %s\n", p.Name, pPath)
}
}
fmt.Println()
}
}
return nil
},
}
var detectInstalledCmd = &cli.Command{
Name: "detect",
Aliases: []string{"d"},
Usage: "detect installed browsers",
Action: func(_ *cli.Context) error {
mods := modules.GetModules()
for _, mod := range mods {
browser, isBrowser := mod.ModInfo().New().(modules.BrowserModule)
if !isBrowser {
log.Debugf("module <%s> is not a browser", mod.ModInfo().ID)
continue
}
pm, isProf := browser.(profiles.ProfileManager)
if !isProf {
log.Debugf("module <%s> is not a profile manager", mod.ModInfo().ID)
continue
}
flavours := pm.ListFlavours()
if len(flavours) > 0 {
fmt.Printf("Installed browsers:\n\n")
}
for _, f := range flavours {
log.Debugf("found flavour <%s> for <%s>", f.Name, mod.ModInfo().ID)
if dir, err := utils.ExpandPath(f.BaseDir); err != nil {
log.Errorf("could not expand path <%s> for flavour <%s>", f.BaseDir, f.Name)
continue
} else {
f.BaseDir = dir
}
fmt.Printf("-%-10s \t %s\n", f.Name, f.BaseDir)
}
}

View File

@ -94,6 +94,18 @@ func GetHomeDir() string {
return user.HomeDir
}
func ExpandPath(paths ...string) string {
return os.ExpandEnv(filepath.Join(paths...))
// ExpandPath expands a path with environment variables and tilde
// Symlinks are followed by default
func ExpandPath(paths ...string) (string, error) {
var homedir string
var err error
if homedir, err = os.UserHomeDir(); err != nil {
return "", err
}
path := os.ExpandEnv(filepath.Join(paths...))
if path[0] == '~' {
path = filepath.Join(homedir, path[1:])
}
return filepath.EvalSymlinks(path)
}

View File

@ -25,24 +25,25 @@ package mozilla
import (
"errors"
"fmt"
"path/filepath"
"regexp"
"git.blob42.xyz/gosuki/gosuki/internal/logging"
_debug "git.blob42.xyz/gosuki/gosuki/pkg/profiles"
"git.blob42.xyz/gosuki/gosuki/internal/utils"
"git.blob42.xyz/gosuki/gosuki/pkg/profiles"
"github.com/go-ini/ini"
)
// ProfileManager interface
type ProfileManager = _debug.ProfileManager
type INIProfileLoader = _debug.INIProfileLoader
type PathGetter = _debug.PathGetter
const (
ProfilesFile = "profiles.ini"
)
// Browser flavour names
const (
FirefoxFlavour = "firefox"
LibreWolfFlavour = "librewolf"
)
var (
log = logging.GetLogger("mozilla")
ReIniProfiles = regexp.MustCompile(`(?i)profile`)
@ -50,47 +51,62 @@ var (
ErrProfilesIni = errors.New("could not parse profiles.ini file")
ErrNoDefaultProfile = errors.New("no default profile found")
// Common default profiles for mozilla/firefox based browsers
DefaultProfileNames = map[string]string{
"firefox-esr": "default-esr",
//TODO: multi platform
// linux mozilla browsers
MozBrowsers = map[string]profiles.BrowserFlavour{
FirefoxFlavour: { FirefoxFlavour , "~/.mozilla/firefox"} ,
LibreWolfFlavour: { LibreWolfFlavour , "~/.librewolf"} ,
}
)
type MozProfileManager struct {
BrowserName string
ConfigDir string
ProfilesFile *ini.File
PathGetter PathGetter
ProfileManager
PathResolver profiles.PathResolver
}
func (pm *MozProfileManager) loadProfile() error {
func NewMozProfileManager(resolver profiles.PathResolver) *MozProfileManager {
log.Debugf("loading profile from <%s>", pm.PathGetter.GetPath())
pFile, err := ini.Load(pm.PathGetter.GetPath())
if err != nil {
return err
return &MozProfileManager{
PathResolver: resolver,
}
pm.ProfilesFile = pFile
return nil
}
func (pm *MozProfileManager) GetProfiles() ([]*_debug.Profile, error) {
err := pm.loadProfile()
func (pm *MozProfileManager) loadINIProfile(r profiles.PathResolver) (*ini.File, error) {
log.Debugf("loading profile from <%s>", r.GetPath())
profilePath, err := utils.ExpandPath(r.GetPath())
if err != nil {
return nil, err
}
sections := pm.ProfilesFile.Sections()
var filtered []*ini.Section
var result []*_debug.Profile
pFile, err := ini.Load(profilePath)
if err != nil {
return nil, err
}
return pFile, nil
}
//TODO: should also handle flavours
func (pm *MozProfileManager) GetProfiles(flavour string) ([]*profiles.Profile, error) {
var pFile *ini.File
var err error
f, ok := MozBrowsers[flavour]
if !ok {
return nil, fmt.Errorf("unknown flavour <%s>", flavour)
}
pm.PathResolver.SetBaseDir(f.BaseDir)
if pFile, err = pm.loadINIProfile(pm.PathResolver); err != nil {
return nil, err
}
sections := pFile.Sections()
var result []*profiles.Profile
for _, section := range sections {
if ReIniProfiles.MatchString(section.Name()) {
filtered = append(filtered, section)
p := &_debug.Profile{
p := &profiles.Profile{
Id: section.Name(),
BaseDir: f.BaseDir,
}
err := section.MapTo(p)
@ -98,32 +114,28 @@ func (pm *MozProfileManager) GetProfiles() ([]*_debug.Profile, error) {
return nil, err
}
result = append(result, p)
}
}
if len(result) == 0 {
return nil, ErrProfilesIni
}
return result, nil
}
// TODO!: ConfigDir is stored in the profile, stop using ConfigDir in the base
// profile manager
// GetProfilePath returns the absolute directory path to a mozilla profile.
func (pm *MozProfileManager) GetProfilePath(name string) (string, error) {
log.Debugf("using config dir %s", pm.ConfigDir)
p, err := pm.GetProfileByName(name)
if err != nil {
return "", err
}
rawPath := filepath.Join(pm.ConfigDir, p.Path)
fullPath , err := filepath.EvalSymlinks(rawPath)
//TODO!: fix the mess of GetProfilePath and GetProfielPathByName
// one method has to be moved as a function
// func (pm *MozProfileManager) GetProfilePath(prof profiles.Profile) (string, error) {
// return utils.ExpandPath(p.BaseDir, p.Path)
// }
return fullPath, err
// Eval symlinks
}
func (pm *MozProfileManager) GetProfileByName(name string) (*_debug.Profile, error) {
profs, err := pm.GetProfiles()
func (pm *MozProfileManager) GetProfileByName(flavour string, name string) (*profiles.Profile, error) {
profs, err := pm.GetProfiles(flavour)
if err != nil {
return nil, err
}
@ -137,41 +149,15 @@ func (pm *MozProfileManager) GetProfileByName(name string) (*_debug.Profile, err
return nil, fmt.Errorf("profile %s not found", name)
}
// TEST:
func (pm *MozProfileManager) GetDefaultProfile() (*_debug.Profile, error) {
profs, err := pm.GetProfiles()
if err != nil {
return nil, err
}
func (pm *MozProfileManager) ListFlavours() []profiles.BrowserFlavour {
var result []profiles.BrowserFlavour
defaultProfileName, ok := DefaultProfileNames[pm.BrowserName]
if !ok {
defaultProfileName = "default"
}
log.Debugf("looking for profile %s", defaultProfileName)
for _, p := range profs {
if p.Name == defaultProfileName {
return p, nil
// detect local flavours
for _, v := range MozBrowsers {
if v.Detect() {
result = append(result, v)
}
}
return nil, ErrNoDefaultProfile
}
func (pm *MozProfileManager) ListProfiles() ([]string, error) {
pm.loadProfile()
sections := pm.ProfilesFile.SectionStrings()
var result []string
for _, s := range sections {
if ReIniProfiles.MatchString(s) {
result = append(result, s)
}
}
if len(result) == 0 {
return nil, ErrProfilesIni
}
return result, nil
return result
}

View File

@ -1,12 +1,12 @@
package mozilla
import (
"testing"
"git.blob42.xyz/gosuki/gosuki/pkg/profiles"
"github.com/stretchr/testify/assert"
"testing"
)
var OkProfile = &INIProfileLoader{
var OkProfile = &profiles.INIProfileLoader{
BasePath: "testdata",
ProfilesFile: "profiles_ok.ini",
}
@ -21,49 +21,15 @@ var okNames = []string{
"profile1",
}
var BadProfile = &INIProfileLoader{
var BadProfile = &profiles.INIProfileLoader{
BasePath: "testdata",
ProfilesFile: "profiles_bad.ini",
}
func TestListProfiles(t *testing.T) {
func TestGetProfiles(t *testing.T) {
t.Run("OK", func(t *testing.T) {
pm := &MozProfileManager{
PathGetter: OkProfile,
}
t.Log("Listing profiles")
profiles, err := pm.ListProfiles()
if err != nil {
t.Error(err)
}
for _, p := range profiles {
t.Logf("found profiles: %s", p)
}
if profiles[0] != "Profile0" {
t.Error("Expected Profile0")
}
})
t.Run("Bad", func(t *testing.T) {
pm := &MozProfileManager{
PathGetter: BadProfile,
}
_, err := pm.ListProfiles()
if err != ErrProfilesIni || err == nil {
t.Error("Expected error parsing bad profiles file")
}
})
}
func TestGetProfiles(t *testing.T) {
pm := &MozProfileManager{
PathGetter: OkProfile,
PathResolver: OkProfile,
}
profs, err := pm.GetProfiles()
@ -71,7 +37,6 @@ func TestGetProfiles(t *testing.T) {
t.Error(err)
}
var pPaths []string
var pNames []string
for _, p := range profs {
@ -87,4 +52,15 @@ func TestGetProfiles(t *testing.T) {
if profs[0].Name != "default" {
t.Error("Expected default profile in profiles.ini")
}
})
t.Run("Bad", func(t *testing.T) {
pm := &MozProfileManager{
PathResolver: BadProfile,
}
_, err := pm.GetProfiles()
if err != ErrProfilesIni || err == nil {
t.Error("Expected error parsing bad profiles file")
}
})
}

View File

@ -1,16 +1,2 @@
#
# Copyright ⓒ 2023 Chakib Ben Ziane <contact@blob42.xyz> and [`GoSuki` contributors](https://github.com/blob42/gosuki/graphs/contributors).
#
# All rights reserved.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This file is part of GoSuki.
#
# GoSuki is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
#
# GoSuki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License along with gosuki. If not, see <http://www.gnu.org/licenses/>.
[Test]
Name=Does not contain a firefox profile

View File

@ -23,8 +23,6 @@ package modules
import (
"fmt"
"path"
"path/filepath"
"time"
"git.blob42.xyz/gosuki/gosuki/hooks"
@ -116,7 +114,7 @@ func (b *BrowserConfig) GetWatcher() *watch.WatchDescriptor {
func (b BrowserConfig) BookmarkDir() (string, error) {
var err error
bDir, err := filepath.EvalSymlinks(utils.ExpandPath(b.BkDir))
bDir, err := utils.ExpandPath(b.BkDir)
if err != nil {
return "", err
}
@ -171,8 +169,7 @@ func (b BrowserConfig) HasHook(hook hooks.Hook) bool {
// It expands the path by concatenating the base directory and bookmarks file,
// then checks if it exists.
func (b BrowserConfig) BookmarkPath() (string, error) {
bPath, err := filepath.EvalSymlinks(path.Join(utils.ExpandPath(b.BkDir),
b.BkFile))
bPath, err := utils.ExpandPath(b.BkDir, b.BkFile)
if err != nil {
log.Error(err)
}

View File

@ -32,3 +32,7 @@ type INIProfileLoader struct {
func (pg *INIProfileLoader) GetPath() string {
return filepath.Join(pg.BasePath, pg.ProfilesFile)
}
func (pg *INIProfileLoader) SetBaseDir(dir string) {
pg.BasePath = dir
}

View File

@ -22,33 +22,40 @@
// Package profiles ...
package profiles
// go:build linux
const (
XDGHome = "XDG_CONFIG_HOME"
import (
"git.blob42.xyz/gosuki/gosuki/internal/logging"
"git.blob42.xyz/gosuki/gosuki/internal/utils"
)
var log = logging.GetLogger("profiles")
// ProfileManager is any module that can detect or list profiles, usually a browser module.
// One profile manager should be created for each browser flavour.
type ProfileManager interface {
// Get all profile details
GetProfiles() ([]*Profile, error)
// Returns all profiles for a given flavour
GetProfiles(flavour string) ([]*Profile, error)
//TODO!: remove
// Returns the default profile if no profile is selected
GetDefaultProfile() (*Profile, error)
// GetDefaultProfile() (*Profile, error)
//TODO!: remove
//TODO!: fix input to method, should take string ?
// Return that absolute path to a profile and follow symlinks
GetProfilePath(Profile) (string)
// GetProfilePath(Profile) (string)
// If should watch all profiles
WatchAllProfiles() bool
// Notifies the module to use a custom profile
UseProfile(p Profile) error
// Returns all flavours supported by this module
ListFlavours() []BrowserFlavour
}
type Profile struct {
// Unique identifier for the profile
Id string
@ -56,10 +63,44 @@ type Profile struct {
// Name of the profile
Name string
// relative path to profile
// relative path to profile from base dir
Path string
// Base dir of the profile
BaseDir string
}
type PathGetter interface {
GetPath() string
func (f Profile) AbsolutePath() (string, error) {
return utils.ExpandPath(f.BaseDir, f.Path)
}
// PathResolver allows custom path resolution for profiles
// See the INIProfileLoader for an example
type PathResolver interface {
GetPath() string
SetBaseDir(string)
}
// The BrowserFlavour struct stores the name of the browser and the base
// directory where the profiles are stored.
// Example flavours: chrome-stable, chrome-unstable, firefox, firefox-esr, librewolf, etc.
type BrowserFlavour struct {
Name string
BaseDir string
}
// Detect if the browser is installed. Returns true if the path exists
func (b BrowserFlavour) Detect() bool {
var dir string
var err error
if dir, err = utils.ExpandPath(b.BaseDir); err != nil {
log.Warningf("could not expand path <%s>: %s", b.BaseDir, err)
return false
} else if _, err = utils.CheckDirExists(dir); err != nil {
log.Warningf("could not find browser <%s> at <%s>: %s", b.Name, dir, err)
return false
}
return true
}