2015-08-31 00:09:28 +00:00
|
|
|
package lfs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
|
2016-11-15 17:01:18 +00:00
|
|
|
"github.com/git-lfs/git-lfs/git"
|
2015-08-31 00:09:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Attribute wraps the structure and some operations of Git's conception of an
|
|
|
|
// "attribute", as defined here: http://git-scm.com/docs/gitattributes.
|
|
|
|
type Attribute struct {
|
2015-09-02 18:57:09 +00:00
|
|
|
// The Section of an Attribute refers to the location at which all
|
|
|
|
// properties are relative to. For example, for a Section with the value
|
|
|
|
// "core", Git will produce something like:
|
2015-08-31 00:09:28 +00:00
|
|
|
//
|
|
|
|
// [core]
|
|
|
|
// autocrlf = true
|
|
|
|
// ...
|
2015-09-02 18:57:09 +00:00
|
|
|
Section string
|
2015-08-31 00:09:28 +00:00
|
|
|
|
|
|
|
// The Properties of an Attribute refer to all of the keys and values
|
|
|
|
// that define that Attribute.
|
|
|
|
Properties map[string]string
|
2016-09-01 11:29:49 +00:00
|
|
|
// Previous values of these attributes that can be automatically upgraded
|
|
|
|
Upgradeables map[string][]string
|
2015-08-31 00:09:28 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 21:19:21 +00:00
|
|
|
// FilterOptions serves as an argument to Install().
|
|
|
|
type FilterOptions struct {
|
2017-10-25 22:12:29 +00:00
|
|
|
GitConfig *git.Configuration
|
2017-10-18 21:19:21 +00:00
|
|
|
Force bool
|
|
|
|
Local bool
|
2020-06-15 22:10:28 +00:00
|
|
|
Worktree bool
|
2017-10-18 21:19:21 +00:00
|
|
|
System bool
|
|
|
|
SkipSmudge bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *FilterOptions) Install() error {
|
|
|
|
if o.SkipSmudge {
|
|
|
|
return skipSmudgeFilterAttribute().Install(o)
|
|
|
|
}
|
|
|
|
return filterAttribute().Install(o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *FilterOptions) Uninstall() error {
|
command/uninstall: report errors and correct usage
When uninstalling, if any "git config --remove-section" commands
failed, we would previously ignore the error and proceed without
reporting it.
We now at least report the errors in a warning message printed to
standard output, akin to the handling introduced to the
"git lfs install" command in PR #2673.
However, we likely can not alter the uninstall behaviour further
and actually exit with an error code in these cases (skipping
any attemp to uninstall our hooks) because users may depend on
the existing willingness of "git lfs uninstall" to try to
uninstall as much as possible, and may have scripts which
depend on this behaviour. Thus we don't call os.Exit(2) in
the manner introduced to "git lfs install" in PR #3624.
On the one hand, this change means users who run an uninstall
command when no relevant Git LFS filter configurations exist
will see a "WARNING" message which may look somewhat scary.
On the other hand, we already report other errors such as
"no such file or directory" when hooks do not exist, and
by reporting these git-config(1) errors we will be able to
better support new options such as --worktree, where
git-config may report error conditions such as when the
worktreeConfig extension is not properly defined yet.
So on balance, we aim for more rather than less error
reporting.
And separately, although the usage text for all command options is
unused (because we override Cobra's usage function in run.go to
always show the man page text instead), we still correct it here
before we add any new options.
2020-06-16 00:55:17 +00:00
|
|
|
return filterAttribute().Uninstall(o)
|
2017-10-18 21:19:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func filterAttribute() *Attribute {
|
|
|
|
return &Attribute{
|
|
|
|
Section: "filter.lfs",
|
|
|
|
Properties: map[string]string{
|
|
|
|
"clean": "git-lfs clean -- %f",
|
|
|
|
"smudge": "git-lfs smudge -- %f",
|
|
|
|
"process": "git-lfs filter-process",
|
|
|
|
"required": "true",
|
|
|
|
},
|
2018-05-04 16:07:25 +00:00
|
|
|
Upgradeables: map[string][]string{
|
|
|
|
"clean": []string{
|
|
|
|
"git-lfs clean %f",
|
|
|
|
},
|
|
|
|
"smudge": []string{
|
|
|
|
"git-lfs smudge %f",
|
|
|
|
"git-lfs smudge --skip %f",
|
|
|
|
"git-lfs smudge --skip -- %f",
|
|
|
|
},
|
|
|
|
"process": []string{
|
|
|
|
"git-lfs filter",
|
|
|
|
"git-lfs filter --skip",
|
|
|
|
"git-lfs filter-process --skip",
|
|
|
|
},
|
|
|
|
},
|
2017-10-18 21:19:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func skipSmudgeFilterAttribute() *Attribute {
|
|
|
|
return &Attribute{
|
|
|
|
Section: "filter.lfs",
|
|
|
|
Properties: map[string]string{
|
|
|
|
"clean": "git-lfs clean -- %f",
|
|
|
|
"smudge": "git-lfs smudge --skip -- %f",
|
|
|
|
"process": "git-lfs filter-process --skip",
|
|
|
|
"required": "true",
|
|
|
|
},
|
2018-05-04 16:07:25 +00:00
|
|
|
Upgradeables: map[string][]string{
|
|
|
|
"clean": []string{
|
|
|
|
"git-lfs clean -- %f",
|
|
|
|
},
|
|
|
|
"smudge": []string{
|
|
|
|
"git-lfs smudge %f",
|
|
|
|
"git-lfs smudge --skip %f",
|
|
|
|
"git-lfs smudge -- %f",
|
|
|
|
},
|
|
|
|
"process": []string{
|
|
|
|
"git-lfs filter",
|
|
|
|
"git-lfs filter --skip",
|
|
|
|
"git-lfs filter-process",
|
|
|
|
},
|
2017-10-18 21:19:21 +00:00
|
|
|
},
|
|
|
|
}
|
2015-09-23 17:58:16 +00:00
|
|
|
}
|
|
|
|
|
2015-09-02 18:57:09 +00:00
|
|
|
// Install instructs Git to set all keys and values relative to the root
|
|
|
|
// location of this Attribute. For any particular key/value pair, if a matching
|
|
|
|
// key is already set, it will be overridden if it is either a) empty, or b) the
|
2015-08-31 00:09:28 +00:00
|
|
|
// `force` argument is passed as true. If an attribute is already set to a
|
|
|
|
// different value than what is given, and force is false, an error will be
|
|
|
|
// returned immediately, and the rest of the attributes will not be set.
|
2017-10-18 21:19:21 +00:00
|
|
|
func (a *Attribute) Install(opt *FilterOptions) error {
|
2015-08-31 00:09:28 +00:00
|
|
|
for k, v := range a.Properties {
|
2016-09-01 11:29:49 +00:00
|
|
|
var upgradeables []string
|
|
|
|
if a.Upgradeables != nil {
|
|
|
|
// use pre-normalised key since caller will have set up the same
|
|
|
|
upgradeables = a.Upgradeables[k]
|
|
|
|
}
|
2015-09-02 18:57:09 +00:00
|
|
|
key := a.normalizeKey(k)
|
2017-10-25 22:12:29 +00:00
|
|
|
if err := a.set(opt.GitConfig, key, v, upgradeables, opt); err != nil {
|
2015-08-31 00:09:28 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-09-02 18:57:09 +00:00
|
|
|
// normalizeKey makes an absolute path out of a partial relative one. For a
|
|
|
|
// relative path of "foo", and a root Section of "bar", "bar.foo" will be returned.
|
|
|
|
func (a *Attribute) normalizeKey(relative string) string {
|
|
|
|
return strings.Join([]string{a.Section, relative}, ".")
|
2015-08-31 00:09:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set attempts to set a single key/value pair portion of this Attribute. If a
|
|
|
|
// matching key already exists and the value is not equal to the desired value,
|
|
|
|
// an error will be thrown if force is set to false. If force is true, the value
|
|
|
|
// will be overridden.
|
2017-10-25 22:12:29 +00:00
|
|
|
func (a *Attribute) set(gitConfig *git.Configuration, key, value string, upgradeables []string, opt *FilterOptions) error {
|
2015-09-23 17:58:16 +00:00
|
|
|
var currentValue string
|
|
|
|
if opt.Local {
|
2017-10-25 22:12:29 +00:00
|
|
|
currentValue = gitConfig.FindLocal(key)
|
2020-06-15 22:10:28 +00:00
|
|
|
} else if opt.Worktree {
|
|
|
|
currentValue = gitConfig.FindWorktree(key)
|
2016-04-26 06:26:02 +00:00
|
|
|
} else if opt.System {
|
2017-10-25 22:12:29 +00:00
|
|
|
currentValue = gitConfig.FindSystem(key)
|
2015-09-23 17:58:16 +00:00
|
|
|
} else {
|
2017-10-25 22:12:29 +00:00
|
|
|
currentValue = gitConfig.FindGlobal(key)
|
2015-09-23 17:58:16 +00:00
|
|
|
}
|
|
|
|
|
2016-09-01 11:29:49 +00:00
|
|
|
if opt.Force || shouldReset(currentValue, upgradeables) {
|
2016-04-26 23:24:00 +00:00
|
|
|
var err error
|
2015-09-23 17:58:16 +00:00
|
|
|
if opt.Local {
|
2017-10-26 01:20:35 +00:00
|
|
|
_, err = gitConfig.SetLocal(key, value)
|
2020-06-15 22:10:28 +00:00
|
|
|
} else if opt.Worktree {
|
|
|
|
_, err = gitConfig.SetWorktree(key, value)
|
2016-04-26 06:26:02 +00:00
|
|
|
} else if opt.System {
|
2017-10-25 22:12:29 +00:00
|
|
|
_, err = gitConfig.SetSystem(key, value)
|
2015-09-23 17:58:16 +00:00
|
|
|
} else {
|
2017-10-25 22:12:29 +00:00
|
|
|
_, err = gitConfig.SetGlobal(key, value)
|
2015-09-23 17:58:16 +00:00
|
|
|
}
|
2016-04-26 23:24:00 +00:00
|
|
|
return err
|
2015-08-31 00:09:28 +00:00
|
|
|
} else if currentValue != value {
|
2019-10-22 07:15:05 +00:00
|
|
|
return fmt.Errorf("the %q attribute should be %q but is %q",
|
2015-08-31 00:09:28 +00:00
|
|
|
key, value, currentValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uninstall removes all properties in the path of this property.
|
command/uninstall: report errors and correct usage
When uninstalling, if any "git config --remove-section" commands
failed, we would previously ignore the error and proceed without
reporting it.
We now at least report the errors in a warning message printed to
standard output, akin to the handling introduced to the
"git lfs install" command in PR #2673.
However, we likely can not alter the uninstall behaviour further
and actually exit with an error code in these cases (skipping
any attemp to uninstall our hooks) because users may depend on
the existing willingness of "git lfs uninstall" to try to
uninstall as much as possible, and may have scripts which
depend on this behaviour. Thus we don't call os.Exit(2) in
the manner introduced to "git lfs install" in PR #3624.
On the one hand, this change means users who run an uninstall
command when no relevant Git LFS filter configurations exist
will see a "WARNING" message which may look somewhat scary.
On the other hand, we already report other errors such as
"no such file or directory" when hooks do not exist, and
by reporting these git-config(1) errors we will be able to
better support new options such as --worktree, where
git-config may report error conditions such as when the
worktreeConfig extension is not properly defined yet.
So on balance, we aim for more rather than less error
reporting.
And separately, although the usage text for all command options is
unused (because we override Cobra's usage function in run.go to
always show the man page text instead), we still correct it here
before we add any new options.
2020-06-16 00:55:17 +00:00
|
|
|
func (a *Attribute) Uninstall(opt *FilterOptions) error {
|
|
|
|
var err error
|
2017-01-24 23:33:29 +00:00
|
|
|
if opt.Local {
|
command/uninstall: report errors and correct usage
When uninstalling, if any "git config --remove-section" commands
failed, we would previously ignore the error and proceed without
reporting it.
We now at least report the errors in a warning message printed to
standard output, akin to the handling introduced to the
"git lfs install" command in PR #2673.
However, we likely can not alter the uninstall behaviour further
and actually exit with an error code in these cases (skipping
any attemp to uninstall our hooks) because users may depend on
the existing willingness of "git lfs uninstall" to try to
uninstall as much as possible, and may have scripts which
depend on this behaviour. Thus we don't call os.Exit(2) in
the manner introduced to "git lfs install" in PR #3624.
On the one hand, this change means users who run an uninstall
command when no relevant Git LFS filter configurations exist
will see a "WARNING" message which may look somewhat scary.
On the other hand, we already report other errors such as
"no such file or directory" when hooks do not exist, and
by reporting these git-config(1) errors we will be able to
better support new options such as --worktree, where
git-config may report error conditions such as when the
worktreeConfig extension is not properly defined yet.
So on balance, we aim for more rather than less error
reporting.
And separately, although the usage text for all command options is
unused (because we override Cobra's usage function in run.go to
always show the man page text instead), we still correct it here
before we add any new options.
2020-06-16 00:55:17 +00:00
|
|
|
_, err = opt.GitConfig.UnsetLocalSection(a.Section)
|
2020-06-15 22:10:28 +00:00
|
|
|
} else if opt.Worktree {
|
|
|
|
_, err = opt.GitConfig.UnsetWorktreeSection(a.Section)
|
2017-01-24 23:33:29 +00:00
|
|
|
} else if opt.System {
|
command/uninstall: report errors and correct usage
When uninstalling, if any "git config --remove-section" commands
failed, we would previously ignore the error and proceed without
reporting it.
We now at least report the errors in a warning message printed to
standard output, akin to the handling introduced to the
"git lfs install" command in PR #2673.
However, we likely can not alter the uninstall behaviour further
and actually exit with an error code in these cases (skipping
any attemp to uninstall our hooks) because users may depend on
the existing willingness of "git lfs uninstall" to try to
uninstall as much as possible, and may have scripts which
depend on this behaviour. Thus we don't call os.Exit(2) in
the manner introduced to "git lfs install" in PR #3624.
On the one hand, this change means users who run an uninstall
command when no relevant Git LFS filter configurations exist
will see a "WARNING" message which may look somewhat scary.
On the other hand, we already report other errors such as
"no such file or directory" when hooks do not exist, and
by reporting these git-config(1) errors we will be able to
better support new options such as --worktree, where
git-config may report error conditions such as when the
worktreeConfig extension is not properly defined yet.
So on balance, we aim for more rather than less error
reporting.
And separately, although the usage text for all command options is
unused (because we override Cobra's usage function in run.go to
always show the man page text instead), we still correct it here
before we add any new options.
2020-06-16 00:55:17 +00:00
|
|
|
_, err = opt.GitConfig.UnsetSystemSection(a.Section)
|
2017-01-24 23:33:29 +00:00
|
|
|
} else {
|
command/uninstall: report errors and correct usage
When uninstalling, if any "git config --remove-section" commands
failed, we would previously ignore the error and proceed without
reporting it.
We now at least report the errors in a warning message printed to
standard output, akin to the handling introduced to the
"git lfs install" command in PR #2673.
However, we likely can not alter the uninstall behaviour further
and actually exit with an error code in these cases (skipping
any attemp to uninstall our hooks) because users may depend on
the existing willingness of "git lfs uninstall" to try to
uninstall as much as possible, and may have scripts which
depend on this behaviour. Thus we don't call os.Exit(2) in
the manner introduced to "git lfs install" in PR #3624.
On the one hand, this change means users who run an uninstall
command when no relevant Git LFS filter configurations exist
will see a "WARNING" message which may look somewhat scary.
On the other hand, we already report other errors such as
"no such file or directory" when hooks do not exist, and
by reporting these git-config(1) errors we will be able to
better support new options such as --worktree, where
git-config may report error conditions such as when the
worktreeConfig extension is not properly defined yet.
So on balance, we aim for more rather than less error
reporting.
And separately, although the usage text for all command options is
unused (because we override Cobra's usage function in run.go to
always show the man page text instead), we still correct it here
before we add any new options.
2020-06-16 00:55:17 +00:00
|
|
|
_, err = opt.GitConfig.UnsetGlobalSection(a.Section)
|
2017-01-24 23:33:29 +00:00
|
|
|
}
|
command/uninstall: report errors and correct usage
When uninstalling, if any "git config --remove-section" commands
failed, we would previously ignore the error and proceed without
reporting it.
We now at least report the errors in a warning message printed to
standard output, akin to the handling introduced to the
"git lfs install" command in PR #2673.
However, we likely can not alter the uninstall behaviour further
and actually exit with an error code in these cases (skipping
any attemp to uninstall our hooks) because users may depend on
the existing willingness of "git lfs uninstall" to try to
uninstall as much as possible, and may have scripts which
depend on this behaviour. Thus we don't call os.Exit(2) in
the manner introduced to "git lfs install" in PR #3624.
On the one hand, this change means users who run an uninstall
command when no relevant Git LFS filter configurations exist
will see a "WARNING" message which may look somewhat scary.
On the other hand, we already report other errors such as
"no such file or directory" when hooks do not exist, and
by reporting these git-config(1) errors we will be able to
better support new options such as --worktree, where
git-config may report error conditions such as when the
worktreeConfig extension is not properly defined yet.
So on balance, we aim for more rather than less error
reporting.
And separately, although the usage text for all command options is
unused (because we override Cobra's usage function in run.go to
always show the man page text instead), we still correct it here
before we add any new options.
2020-06-16 00:55:17 +00:00
|
|
|
return err
|
2015-08-31 00:09:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// shouldReset determines whether or not a value is resettable given its current
|
|
|
|
// value on the system. If the value is empty (length = 0), then it will pass.
|
2016-09-01 11:29:49 +00:00
|
|
|
// It will also pass if it matches any upgradeable value
|
|
|
|
func shouldReset(value string, upgradeables []string) bool {
|
2015-08-31 00:09:28 +00:00
|
|
|
if len(value) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2016-09-01 11:29:49 +00:00
|
|
|
for _, u := range upgradeables {
|
|
|
|
if value == u {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2015-08-31 00:09:28 +00:00
|
|
|
}
|