代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2018 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package advisor
import (
"encoding/json"
"os"
"path/filepath"
"time"
"github.com/snapcore/bolt"
"gitee.com/mysnapcore/mysnapd/dirs"
"gitee.com/mysnapcore/mysnapd/osutil"
"gitee.com/mysnapcore/mysnapd/randutil"
)
var (
cmdBucketKey = []byte("Commands")
pkgBucketKey = []byte("Snaps")
)
type writer struct {
fn string
db *bolt.DB
tx *bolt.Tx
cmdBucket *bolt.Bucket
pkgBucket *bolt.Bucket
}
type CommandDB interface {
// AddSnap adds the entries for commands pointing to the given
// snap name to the commands database.
AddSnap(snapName, version, summary string, commands []string) error
// Commit persist the changes, and closes the database. If the
// database has already been committed/rollbacked, does nothing.
Commit() error
// Rollback aborts the changes, and closes the database. If the
// database has already been committed/rollbacked, does nothing.
Rollback() error
}
// Create opens the commands database for writing, and starts a
// transaction that drops and recreates the buckets. You should then
// call AddSnap with each snap you wish to add, and them Commit the
// results to make the changes live, or Rollback to abort; either of
// these closes the database again.
func Create() (CommandDB, error) {
var err error
t := &writer{
fn: dirs.SnapCommandsDB + "." + randutil.RandomString(12) + "~",
}
t.db, err = bolt.Open(t.fn, 0644, &bolt.Options{Timeout: 1 * time.Second})
if err != nil {
return nil, err
}
t.tx, err = t.db.Begin(true)
if err == nil {
t.cmdBucket, err = t.tx.CreateBucket(cmdBucketKey)
if err == nil {
t.pkgBucket, err = t.tx.CreateBucket(pkgBucketKey)
}
if err != nil {
t.tx.Rollback()
}
}
if err != nil {
t.db.Close()
return nil, err
}
return t, nil
}
func (t *writer) AddSnap(snapName, version, summary string, commands []string) error {
for _, cmd := range commands {
var sil []Package
bcmd := []byte(cmd)
row := t.cmdBucket.Get(bcmd)
if row != nil {
if err := json.Unmarshal(row, &sil); err != nil {
return err
}
}
// For the mapping of command->snap we do not need the summary, nothing is using that.
sil = append(sil, Package{Snap: snapName, Version: version})
row, err := json.Marshal(sil)
if err != nil {
return err
}
if err := t.cmdBucket.Put(bcmd, row); err != nil {
return err
}
}
// TODO: use json here as well and put the version information here
bj, err := json.Marshal(Package{
Snap: snapName,
Version: version,
Summary: summary,
})
if err != nil {
return err
}
if err := t.pkgBucket.Put([]byte(snapName), bj); err != nil {
return err
}
return nil
}
func (t *writer) Commit() error {
// either everything worked, and therefore this will fail, or something
// will fail, and that error is more important than this one if this one
// then fails as well. So, ignore the error.
defer os.Remove(t.fn)
if err := t.done(true); err != nil {
return err
}
dir, err := os.Open(filepath.Dir(dirs.SnapCommandsDB))
if err != nil {
return err
}
defer dir.Close()
if err := os.Rename(t.fn, dirs.SnapCommandsDB); err != nil {
return err
}
return dir.Sync()
}
func (t *writer) Rollback() error {
e1 := t.done(false)
e2 := os.Remove(t.fn)
if e1 == nil {
return e2
}
return e1
}
func (t *writer) done(commit bool) error {
var e1, e2 error
t.cmdBucket = nil
t.pkgBucket = nil
if t.tx != nil {
if commit {
e1 = t.tx.Commit()
} else {
e1 = t.tx.Rollback()
}
t.tx = nil
}
if t.db != nil {
e2 = t.db.Close()
t.db = nil
}
if e1 == nil {
return e2
}
return e1
}
// DumpCommands returns the whole database as a map. For use in
// testing and debugging.
func DumpCommands() (map[string]string, error) {
db, err := bolt.Open(dirs.SnapCommandsDB, 0644, &bolt.Options{
ReadOnly: true,
Timeout: 1 * time.Second,
})
if err != nil {
return nil, err
}
defer db.Close()
tx, err := db.Begin(false)
if err != nil {
return nil, err
}
defer tx.Rollback()
b := tx.Bucket(cmdBucketKey)
if b == nil {
return nil, nil
}
m := map[string]string{}
c := b.Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
m[string(k)] = string(v)
}
return m, nil
}
type boltFinder struct {
*bolt.DB
}
// Open the database for reading.
func Open() (Finder, error) {
// Check for missing file manually to workaround bug in bolt.
// bolt.Open() is using os.OpenFile(.., os.O_RDONLY |
// os.O_CREATE) even if ReadOnly mode is used. So we would get
// a misleading "permission denied" error without this check.
if !osutil.FileExists(dirs.SnapCommandsDB) {
return nil, os.ErrNotExist
}
db, err := bolt.Open(dirs.SnapCommandsDB, 0644, &bolt.Options{
ReadOnly: true,
Timeout: 1 * time.Second,
})
if err != nil {
return nil, err
}
return &boltFinder{db}, nil
}
func (f *boltFinder) FindCommand(command string) ([]Command, error) {
tx, err := f.Begin(false)
if err != nil {
return nil, err
}
defer tx.Rollback()
b := tx.Bucket(cmdBucketKey)
if b == nil {
return nil, nil
}
buf := b.Get([]byte(command))
if buf == nil {
return nil, nil
}
var sil []Package
if err := json.Unmarshal(buf, &sil); err != nil {
return nil, err
}
cmds := make([]Command, len(sil))
for i, si := range sil {
cmds[i] = Command{
Snap: si.Snap,
Version: si.Version,
Command: command,
}
}
return cmds, nil
}
func (f *boltFinder) FindPackage(pkgName string) (*Package, error) {
tx, err := f.Begin(false)
if err != nil {
return nil, err
}
defer tx.Rollback()
b := tx.Bucket(pkgBucketKey)
if b == nil {
return nil, nil
}
bj := b.Get([]byte(pkgName))
if bj == nil {
return nil, nil
}
var si Package
err = json.Unmarshal(bj, &si)
if err != nil {
return nil, err
}
return &Package{Snap: pkgName, Version: si.Version, Summary: si.Summary}, nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。