mozilla profile manager: handle profiles for many flavours
This commit is contained in:
parent
59eb4b8f5c
commit
ac70d2e3a7
@ -29,48 +29,49 @@ 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{
|
||||
Name: "unlock",
|
||||
Aliases: []string{"u"},
|
||||
Action: ffUnlockVFS,
|
||||
}
|
||||
var (
|
||||
ffUnlockVFSCmd = cli.Command{
|
||||
Name: "unlock",
|
||||
Aliases: []string{"u"},
|
||||
Action: ffUnlockVFS,
|
||||
}
|
||||
|
||||
var ffCheckVFSCmd = cli.Command{
|
||||
Name: "check",
|
||||
Aliases: []string{"c"},
|
||||
Action: ffCheckVFS,
|
||||
}
|
||||
ffCheckVFSCmd = cli.Command{
|
||||
Name: "check",
|
||||
Aliases: []string{"c"},
|
||||
Action: ffCheckVFS,
|
||||
}
|
||||
|
||||
var ffVFSCommands = cli.Command{
|
||||
Name: "vfs",
|
||||
Usage: "VFS locking commands",
|
||||
Subcommands: []*cli.Command{
|
||||
&ffUnlockVFSCmd,
|
||||
ffVFSCommands = cli.Command{
|
||||
Name: "vfs",
|
||||
Usage: "VFS locking commands",
|
||||
Subcommands: []*cli.Command{
|
||||
&ffUnlockVFSCmd,
|
||||
&ffCheckVFSCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var ffListProfilesCmd = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"l"},
|
||||
Action: ffListProfiles,
|
||||
}
|
||||
ffListProfilesCmd = cli.Command{
|
||||
Name: "list",
|
||||
Aliases: []string{"l"},
|
||||
Action: ffListProfiles,
|
||||
}
|
||||
|
||||
var ffProfilesCmds = cli.Command{
|
||||
Name: "profiles",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Profiles commands",
|
||||
Subcommands: []*cli.Command{
|
||||
&ffListProfilesCmd,
|
||||
},
|
||||
}
|
||||
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()
|
||||
if err != nil {
|
||||
return err
|
||||
flavours := FirefoxProfileManager.ListFlavours()
|
||||
for _, f := range flavours {
|
||||
profs, err := FirefoxProfileManager.GetProfiles(f.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, p := range profs {
|
||||
if fullPath, err := p.AbsolutePath(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
fmt.Printf("%-10s \t %s\n", p.Name, fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range profs {
|
||||
fmt.Printf("%-10s \t %s\n", p.Name, utils.ExpandPath(FirefoxProfileManager.ConfigDir, p.Path))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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)
|
||||
|
@ -156,18 +156,21 @@ func startDaemon(c *cli.Context) error {
|
||||
bpm, ok := browser.(profiles.ProfileManager)
|
||||
if ok {
|
||||
if bpm.WatchAllProfiles() {
|
||||
profs, err := bpm.GetProfiles()
|
||||
if err != nil {
|
||||
log.Critical("could not get profiles")
|
||||
continue
|
||||
}
|
||||
for _, p := range profs {
|
||||
log.Debugf("profile: <%s>", p.Name)
|
||||
err = runModule(manager, c, browserMod, p)
|
||||
falvours := bpm.ListFlavours()
|
||||
for _, f := range falvours {
|
||||
profs, err := bpm.GetProfiles(f.Name)
|
||||
if err != nil {
|
||||
log.Critical(err)
|
||||
log.Critical("could not get profiles")
|
||||
continue
|
||||
}
|
||||
for _, p := range profs {
|
||||
log.Debugf("profile: <%s>", p.Name)
|
||||
err = runModule(manager, c, browserMod, p)
|
||||
if err != nil {
|
||||
log.Critical(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Debugf("profile manager <%s> not watching all profiles",
|
||||
|
@ -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()
|
||||
|
@ -82,4 +82,3 @@ var listModulesCmd = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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,24 +62,68 @@ 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()
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
fmt.Printf("%-10s \t %s\n", p.Name, pPath)
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range profs {
|
||||
fmt.Printf("%-10s \t %s\n", p.Name, pm.GetProfilePath(*p))
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
return &MozProfileManager{
|
||||
PathResolver: resolver,
|
||||
}
|
||||
}
|
||||
|
||||
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 err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pFile, err := ini.Load(profilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pm.ProfilesFile = pFile
|
||||
return nil
|
||||
return pFile, nil
|
||||
}
|
||||
|
||||
func (pm *MozProfileManager) GetProfiles() ([]*_debug.Profile, error) {
|
||||
err := pm.loadProfile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//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]
|
||||
|
||||
sections := pm.ProfilesFile.Sections()
|
||||
var filtered []*ini.Section
|
||||
var result []*_debug.Profile
|
||||
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
|
||||
}
|
||||
|
@ -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,70 +21,46 @@ 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,
|
||||
PathResolver: OkProfile,
|
||||
}
|
||||
|
||||
t.Log("Listing profiles")
|
||||
profiles, err := pm.ListProfiles()
|
||||
profs, err := pm.GetProfiles()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for _, p := range profiles {
|
||||
t.Logf("found profiles: %s", p)
|
||||
var pPaths []string
|
||||
var pNames []string
|
||||
for _, p := range profs {
|
||||
pPaths = append(pPaths, p.Path)
|
||||
pNames = append(pNames, p.Name)
|
||||
|
||||
//TEST: Test the absolute path
|
||||
|
||||
}
|
||||
if profiles[0] != "Profile0" {
|
||||
t.Error("Expected Profile0")
|
||||
assert.ElementsMatch(t, okPaths, pPaths)
|
||||
assert.ElementsMatch(t, okNames, pNames)
|
||||
|
||||
if profs[0].Name != "default" {
|
||||
t.Error("Expected default profile in profiles.ini")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Bad", func(t *testing.T) {
|
||||
pm := &MozProfileManager{
|
||||
PathGetter: BadProfile,
|
||||
PathResolver: BadProfile,
|
||||
}
|
||||
|
||||
_, err := pm.ListProfiles()
|
||||
|
||||
_, err := pm.GetProfiles()
|
||||
if err != ErrProfilesIni || err == nil {
|
||||
t.Error("Expected error parsing bad profiles file")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestGetProfiles(t *testing.T) {
|
||||
pm := &MozProfileManager{
|
||||
PathGetter: OkProfile,
|
||||
|
||||
}
|
||||
|
||||
profs, err := pm.GetProfiles()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
|
||||
var pPaths []string
|
||||
var pNames []string
|
||||
for _, p := range profs {
|
||||
pPaths = append(pPaths, p.Path)
|
||||
pNames = append(pNames, p.Name)
|
||||
|
||||
//TEST: Test the absolute path
|
||||
|
||||
}
|
||||
assert.ElementsMatch(t, okPaths, pPaths)
|
||||
assert.ElementsMatch(t, okNames, pNames)
|
||||
|
||||
if profs[0].Name != "default" {
|
||||
t.Error("Expected default profile in profiles.ini")
|
||||
}
|
||||
}
|
||||
|
14
pkg/browsers/mozilla/testdata/profiles_bad.ini
vendored
14
pkg/browsers/mozilla/testdata/profiles_bad.ini
vendored
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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"
|
||||
)
|
||||
|
||||
// ProfileManager is any module that can detect or list profiles, usually a browser module.
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user