wip cli + profile handling
This commit is contained in:
parent
5cbcf816a7
commit
9ed35b4149
36
commands.go
36
commands.go
@ -1,8 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gomark/mozilla"
|
||||
"gomark/parsing"
|
||||
"gomark/utils"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.sp4ke.com/sp4ke/gum"
|
||||
"github.com/urfave/cli"
|
||||
@ -15,6 +18,39 @@ var startServerCmd = cli.Command{
|
||||
Action: startServer,
|
||||
}
|
||||
|
||||
var unlockFirefoxCmd = cli.Command{
|
||||
Name: "ff",
|
||||
Usage: "Disable VFS lock in firefox",
|
||||
Action: unlockFirefox,
|
||||
}
|
||||
|
||||
func unlockFirefox(c *cli.Context) {
|
||||
prefsPath := path.Join(mozilla.BookmarkDir, mozilla.PrefsFile)
|
||||
|
||||
pusers, err := utils.FileProcessUsers(path.Join(mozilla.BookmarkDir, mozilla.BookmarkFile))
|
||||
if err != nil {
|
||||
fflog.Error(err)
|
||||
}
|
||||
|
||||
for pid, p := range pusers {
|
||||
pname, err := p.Name()
|
||||
if err != nil {
|
||||
fflog.Error(err)
|
||||
}
|
||||
log.Errorf("multiprocess not enabled and %s(%d) is running. Close firefox and disable VFS lock", pname, pid)
|
||||
}
|
||||
// End testing
|
||||
|
||||
// enable multi process access in firefox
|
||||
err = mozilla.SetPrefBool(prefsPath,
|
||||
mozilla.PrefMultiProcessAccess,
|
||||
true)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func startServer(c *cli.Context) {
|
||||
manager := gum.NewManager()
|
||||
manager.ShutdownOn(os.Interrupt)
|
||||
|
1
main.go
1
main.go
@ -18,6 +18,7 @@ func main() {
|
||||
|
||||
app.Commands = []cli.Command{
|
||||
startServerCmd,
|
||||
unlockFirefoxCmd,
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
|
@ -1,11 +1,7 @@
|
||||
package mozilla
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gomark/logging"
|
||||
"gomark/utils"
|
||||
"path"
|
||||
)
|
||||
|
||||
var fflog = logging.GetLogger("FF")
|
||||
@ -15,22 +11,6 @@ const (
|
||||
BookmarkDir = "/home/spike/.mozilla/firefox/7otsk3vs.test_bookmarks"
|
||||
)
|
||||
|
||||
const (
|
||||
// This option disables the VFS lock on firefox
|
||||
// Sqlite allows file locking of the database using the local file system VFS.
|
||||
// Previous versions of FF allowed external processes to access the file.
|
||||
//
|
||||
// Since firefox v(63) this has changed. When initializing the database FF checks
|
||||
// the preference option `storage.multiProcessAccess.enabled` which is not
|
||||
// documented officially.
|
||||
//
|
||||
// Source code:
|
||||
//- https://dxr.mozilla.org/mozilla-central/source/storage/TelemetryVFS.cpp#884
|
||||
//- https://dxr.mozilla.org/mozilla-central/source/storage/mozStorageService.cpp#377
|
||||
//- Change on github: https://github.com/mozilla/gecko-dev/commit/a543f35d4be483b19446304f52e4781d7a4a0a2f
|
||||
PrefMultiProcessAccess = "storage.multiProcessAccess.enabled"
|
||||
)
|
||||
|
||||
var (
|
||||
// Default data source name query options for `places.sqlite` db
|
||||
PlacesDSN = map[string]string{
|
||||
@ -38,63 +18,3 @@ var (
|
||||
}
|
||||
log = logging.GetLogger("MOZ")
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMultiProcessAlreadyEnabled = errors.New("multiProcessAccess already enabled")
|
||||
)
|
||||
|
||||
//TODO: try unlock at the browser level !
|
||||
// Try to unlock vfs locked places.sqlite by setting the `PrefMultiProcessAccess`
|
||||
// property in prefs.js
|
||||
|
||||
func UnlockPlaces(dir string) error {
|
||||
log.Debug("Unlocking places.sqlite ...")
|
||||
|
||||
prefsPath := path.Join(dir, PrefsFile)
|
||||
|
||||
// Find if multiProcessAccess option is defined
|
||||
|
||||
pref, err := GetPrefBool(prefsPath, PrefMultiProcessAccess)
|
||||
if err != nil && err != ErrPrefNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
// If pref already defined and true raise an error
|
||||
if pref {
|
||||
log.Criticalf("pref <%s> already defined as <%v>",
|
||||
PrefMultiProcessAccess, pref)
|
||||
return ErrMultiProcessAlreadyEnabled
|
||||
|
||||
// Set the preference
|
||||
} else {
|
||||
|
||||
// Checking if firefox is running
|
||||
// TODO: #multiprocess add CLI to unlock places.sqlite
|
||||
pusers, err := utils.FileProcessUsers(path.Join(BookmarkDir, BookmarkFile))
|
||||
if err != nil {
|
||||
fflog.Error(err)
|
||||
}
|
||||
|
||||
for pid, p := range pusers {
|
||||
pname, err := p.Name()
|
||||
if err != nil {
|
||||
fflog.Error(err)
|
||||
}
|
||||
return errors.New(fmt.Sprintf("multiprocess not enabled and %s(%d) is running", pname, pid))
|
||||
}
|
||||
// End testing
|
||||
|
||||
// enable multi process access in firefox
|
||||
err = SetPrefBool(prefsPath,
|
||||
PrefMultiProcessAccess,
|
||||
true)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
92
mozilla/firefox_profiles.go
Normal file
92
mozilla/firefox_profiles.go
Normal file
@ -0,0 +1,92 @@
|
||||
package mozilla
|
||||
|
||||
import (
|
||||
"gomark/profiles"
|
||||
"gomark/utils"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
ProfilesFile = "profiles.ini"
|
||||
)
|
||||
|
||||
var (
|
||||
ConfigFolder = ".mozilla/firefox"
|
||||
ReIniProfiles = regexp.MustCompile(`(?i)profile`)
|
||||
)
|
||||
|
||||
type FFProfileManager struct {
|
||||
basePath string
|
||||
profilesFile *ini.File
|
||||
}
|
||||
|
||||
func (pm *FFProfileManager) GetProfiles() ([]*profiles.Profile, error) {
|
||||
sections := pm.profilesFile.Sections()
|
||||
var filtered []*ini.Section
|
||||
var result []*profiles.Profile
|
||||
for _, section := range sections {
|
||||
if ReIniProfiles.MatchString(section.Name()) {
|
||||
filtered = append(filtered, section)
|
||||
|
||||
p := &profiles.Profile{
|
||||
Id: section.Name(),
|
||||
}
|
||||
|
||||
err := section.MapTo(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, p)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (pm *FFProfileManager) ListProfiles() []string {
|
||||
sections := pm.profilesFile.SectionStrings()
|
||||
var result []string
|
||||
for _, s := range sections {
|
||||
if ReIniProfiles.MatchString(s) {
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func NewFFProfileManager() (*FFProfileManager, error) {
|
||||
profiles, err := ini.Load(filepath.Join(ConfigFolder, ProfilesFile))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pm := &FFProfileManager{
|
||||
basePath: ConfigFolder,
|
||||
profilesFile: profiles,
|
||||
}
|
||||
|
||||
return pm, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
ConfigFolder = filepath.Join(utils.GetHomeDir(), ConfigFolder)
|
||||
|
||||
// Check if base folder exists
|
||||
configFolderExists, err := utils.CheckDirExists(ConfigFolder)
|
||||
if !configFolderExists {
|
||||
fflog.Criticalf("The base firefox folder <%s> does not exist",
|
||||
ConfigFolder)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fflog.Critical(err)
|
||||
}
|
||||
|
||||
}
|
43
mozilla/firefox_profiles_test.go
Normal file
43
mozilla/firefox_profiles_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
package mozilla
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewProfileManager(t *testing.T) {
|
||||
InitialConfigFolder := ConfigFolder
|
||||
ConfigFolder = "toto"
|
||||
_, err := NewFFProfileManager()
|
||||
|
||||
if !os.IsNotExist(err) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
ConfigFolder = InitialConfigFolder
|
||||
}
|
||||
|
||||
func TestListProfiles(t *testing.T) {
|
||||
pm, _ := NewFFProfileManager()
|
||||
|
||||
t.Log("Listing profiles")
|
||||
profiles := pm.ListProfiles()
|
||||
for _, p := range pm.ListProfiles() {
|
||||
t.Logf("found profiles: %s", p)
|
||||
}
|
||||
if profiles[0] != "Profile0" {
|
||||
t.Error("Expected at least Profile0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProfiles(t *testing.T) {
|
||||
pm, _ := NewFFProfileManager()
|
||||
profs, err := pm.GetProfiles()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
for _, p := range profs {
|
||||
t.Log(p)
|
||||
}
|
||||
}
|
85
mozilla/firefox_vfs.go
Normal file
85
mozilla/firefox_vfs.go
Normal file
@ -0,0 +1,85 @@
|
||||
package mozilla
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gomark/utils"
|
||||
"path"
|
||||
)
|
||||
|
||||
const (
|
||||
// This option disables the VFS lock on firefox
|
||||
// Sqlite allows file locking of the database using the local file system VFS.
|
||||
// Previous versions of FF allowed external processes to access the file.
|
||||
//
|
||||
// Since firefox v(63) this has changed. When initializing the database FF checks
|
||||
// the preference option `storage.multiProcessAccess.enabled` which is not
|
||||
// documented officially.
|
||||
//
|
||||
// Source code:
|
||||
//- https://dxr.mozilla.org/mozilla-central/source/storage/TelemetryVFS.cpp#884
|
||||
//- https://dxr.mozilla.org/mozilla-central/source/storage/mozStorageService.cpp#377
|
||||
//- Change on github: https://github.com/mozilla/gecko-dev/commit/a543f35d4be483b19446304f52e4781d7a4a0a2f
|
||||
PrefMultiProcessAccess = "storage.multiProcessAccess.enabled"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMultiProcessAlreadyEnabled = errors.New("multiProcessAccess already enabled")
|
||||
)
|
||||
|
||||
func UnlockPlaces(dir string) error {
|
||||
log.Debug("Unlocking places.sqlite ...")
|
||||
|
||||
prefsPath := path.Join(dir, PrefsFile)
|
||||
|
||||
// Find if multiProcessAccess option is defined
|
||||
|
||||
pref, err := GetPrefBool(prefsPath, PrefMultiProcessAccess)
|
||||
if err != nil && err != ErrPrefNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
// If pref already defined and true raise an error
|
||||
if pref {
|
||||
log.Criticalf("pref <%s> already defined as <%v>",
|
||||
PrefMultiProcessAccess, pref)
|
||||
return ErrMultiProcessAlreadyEnabled
|
||||
|
||||
// Set the preference
|
||||
} else {
|
||||
|
||||
// Checking if firefox is running
|
||||
// TODO: #multiprocess add CLI to unlock places.sqlite
|
||||
pusers, err := utils.FileProcessUsers(path.Join(BookmarkDir, BookmarkFile))
|
||||
if err != nil {
|
||||
fflog.Error(err)
|
||||
}
|
||||
|
||||
for pid, p := range pusers {
|
||||
pname, err := p.Name()
|
||||
if err != nil {
|
||||
fflog.Error(err)
|
||||
}
|
||||
return errors.New(fmt.Sprintf("multiprocess not enabled and %s(%d) is running. Close firefox and disable VFS lock", pname, pid))
|
||||
}
|
||||
// End testing
|
||||
|
||||
// enable multi process access in firefox
|
||||
err = SetPrefBool(prefsPath,
|
||||
PrefMultiProcessAccess,
|
||||
true)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
//TODO: try unlock at the browser level !
|
||||
// Try to unlock vfs locked places.sqlite by setting the `PrefMultiProcessAccess`
|
||||
// property in prefs.js
|
20
profiles/profiles.go
Normal file
20
profiles/profiles.go
Normal file
@ -0,0 +1,20 @@
|
||||
// +build linux
|
||||
//
|
||||
|
||||
package profiles
|
||||
|
||||
const (
|
||||
XDG_HOME = "XDG_CONFIG_HOME"
|
||||
)
|
||||
|
||||
type ProfileManager interface {
|
||||
ListProfiles() []string
|
||||
GetProfiles() []*Profile
|
||||
GetDefaultProfile() Profile
|
||||
}
|
||||
|
||||
type Profile struct {
|
||||
Id string
|
||||
Name string
|
||||
Path string
|
||||
}
|
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
)
|
||||
|
||||
@ -11,6 +12,15 @@ func GetDefaultDBPath() string {
|
||||
return "./"
|
||||
}
|
||||
|
||||
func CheckDirExists(path string) (bool, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return info.IsDir(), nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
|
||||
func CheckFileExists(file string) (bool, error) {
|
||||
info, err := os.Stat(file)
|
||||
if err == nil {
|
||||
@ -56,3 +66,8 @@ func CheckWriteable(dir string) error {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetHomeDir() string {
|
||||
user, _ := user.Current()
|
||||
return user.HomeDir
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ func FileProcessUsers(path string) (map[int32]*psutil.Process, error) {
|
||||
for _, p := range processes {
|
||||
|
||||
files, err := p.OpenFiles()
|
||||
_, isPathError := err.(*os.PathError)
|
||||
|
||||
if err != nil && isPathError {
|
||||
//TODO: use os.IsNotExist to test the path error
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user