Skip to content
This repository has been archived by the owner on Sep 9, 2020. It is now read-only.

Improve help text #78

Merged
merged 8 commits into from
Jan 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 80 additions & 77 deletions ensure.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,101 +10,90 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"

"io/ioutil"

"github.com/pkg/errors"
"github.com/sdboyer/gps"
)

var ensureCmd = &command{
fn: runEnsure,
name: "ensure",
flag: flag.NewFlagSet("", flag.ExitOnError),
short: `[flags] <path>[:alt location][@<version specifier>]
To ensure a dependency is in your project at a specific version (if specified).
`,
long: `
Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.


What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed


Flags:
-update update all packages
-n dry run
-override <specs> specify an override constraints for package(s)


Package specs:
<path>[:alt location][@<version specifier>]
const ensureShortHelp = `Ensure a dependency is safely vendored in the project`
const ensureLongHelp = `
Ensure is used to fetch project dependencies into the vendor folder, as well as
to set version constraints for specific dependencies. It takes user input,
solves the updated dependency graph of the project, writes any changes to the
manifest and lock file, and places dependencies in the vendor folder.

Package spec:

<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
$ dep ensure github.com/heroku/rollrus==1.2.3 # 1.2.3 specifically
$ dep ensure github.com/heroku/rollrus=^1.2.0 # >= 1.2.0 < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
$ dep ensure -override github.com/foo/bar@^0.9.1


Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".


For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
`,
}

// stringSlice is a slice of strings
type stringSlice []string
dep ensure Populate vendor from existing manifest and lock
dep ensure github.com/pkg/foo@^1.0.1 Update a specific dependency to a specific version

// implement the flag interface for stringSlice
func (s *stringSlice) String() string {
return fmt.Sprintf("%s", *s)
}
func (s *stringSlice) Set(value string) error {
*s = append(*s, value)
return nil
}
For more detailed usage examples, see dep ensure -examples.
`
const ensureExamples = `
dep ensure

Solve the project's dependency graph, and place all dependencies in the
vendor folder. If a dependency is in the lock file, use the version
specified there. Otherwise, use the most recent version that can satisfy the
constraints in the manifest file.

dep ensure github.com/pkg/foo@^1.0.1

Same as above, but choose any release >= 1.0.1, < 2.0.0. If a constraint was
previously set in the manifest, this resets it. This form of constraint
strikes a good balance of safety and flexibility, and should be preferred
for libraries.

dep ensure github.com/pkg/foo@~1.0.1

Same as above, but choose any release matching 1.0.x, preferring latest.

dep ensure github.com/pkg/foo:git.internal.com/alt/foo

var overrides stringSlice
Fetch the dependency from a different location.

func init() {
ensureCmd.flag.Var(&overrides, "override", "Interpret specified constraint(s) as override(s) rather than normal constraints")
dep ensure -override github.com/pkg/foo@^1.0.1

Forcefully and transitively override any constraint for this dependency.
Overrides are powerful, but harmful in the long term. They should be used
as a last resort, especially if your project may be imported by others.
`

func (cmd *ensureCommand) Name() string { return "ensure" }
func (cmd *ensureCommand) Args() string { return "[spec...]" }
func (cmd *ensureCommand) ShortHelp() string { return ensureShortHelp }
func (cmd *ensureCommand) LongHelp() string { return ensureLongHelp }

func (cmd *ensureCommand) Register(fs *flag.FlagSet) {
fs.BoolVar(&cmd.examples, "examples", false, "print detailed usage examples")
fs.BoolVar(&cmd.update, "update", false, "ensure all dependencies are at the latest version allowed by the manifest")
fs.BoolVar(&cmd.dryRun, "n", false, "dry run, don't actually ensure anything")
fs.Var(&cmd.overrides, "override", "specify an override constraint spec (repeatable)")
}

type ensureCommand struct {
examples bool
update bool
dryRun bool
overrides stringSlice
}

func runEnsure(args []string) error {
func (cmd *ensureCommand) Run(args []string) error {
if cmd.examples {
fmt.Fprintln(os.Stderr, strings.TrimSpace(ensureExamples))
return nil
}

p, err := depContext.loadProject("")
if err != nil {
return err
Expand Down Expand Up @@ -152,7 +141,7 @@ func runEnsure(args []string) error {
}
}

for _, ovr := range overrides {
for _, ovr := range cmd.overrides {
pc, err := getProjectConstraint(ovr, sm)
if err != nil {
errs = append(errs, err)
Expand Down Expand Up @@ -261,6 +250,20 @@ func runEnsure(args []string) error {
return nil
}

type stringSlice []string

func (s *stringSlice) String() string {
if len(*s) == 0 {
return "<none>"
}
return strings.Join(*s, ", ")
}

func (s *stringSlice) Set(value string) error {
*s = append(*s, value)
return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
constraint := gps.ProjectConstraint{
Constraint: gps.Any(), // default to any; avoids panics later
Expand Down
67 changes: 31 additions & 36 deletions init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
Expand All @@ -16,47 +17,41 @@ import (
"github.com/sdboyer/gps"
)

var initCmd = &command{
fn: runInit,
name: "init",
short: `
Write Manifest file in the root of the project directory.
`,
long: `
Populates Manifest file with current deps of this project.
The specified version of each dependent repository is the version
available in the user's workspaces (as specified by GOPATH).
If the dependency is not present in any workspaces it is not be
included in the Manifest.
Writes Lock file(?)
Creates vendor/ directory(?)

Notes from DOC:
Reads existing dependency information written by other tools.
Noting any information that is lost (unsupported features, etc).
This functionality will be removed after a transition period (1 year?).
Write Manifest file in the root of the project directory.
* Populates Manifest file with current deps of this project.
The specified version of each dependent repository is the version available in the user's workspaces (including vendor/ directories, if present).
If the dependency is not present in any workspaces it will not be included in the Manifest. A warning will be issued for these dependencies.
Creates vendor/ directory (if it does not exist)
Copies the project’s dependencies from the workspace to the vendor/ directory (if they’re not already there).
Writes a Lockfile in the root of the project directory.
Invoke “dep status”.
`,
}
const initShortHelp = `Initialize a new project with manifest and lock files`
const initLongHelp = `
Initialize the project at filepath root by parsing its dependencies and writing
manifest and lock files. If root isn't specified, use the current directory.

The version of each dependency will reflect the current state of the GOPATH. If
a dependency doesn't exist in the GOPATH, it won't be written to the manifest,
but it will be solved-for, and will appear in the lock.

Note: init may use the network to solve the dependency graph.

Note: init does NOT vendor dependencies at the moment. See dep ensure.
`

func (cmd *initCommand) Name() string { return "init" }
func (cmd *initCommand) Args() string { return "[root]" }
func (cmd *initCommand) ShortHelp() string { return initShortHelp }
func (cmd *initCommand) LongHelp() string { return initLongHelp }

func runInit(args []string) error {
func (cmd *initCommand) Register(fs *flag.FlagSet) {}

type initCommand struct{}

func (cmd *initCommand) Run(args []string) error {
if len(args) > 1 {
return fmt.Errorf("Too many args: %d", len(args))
return errors.Errorf("too many args (%d)", len(args))
}

var root string
var err error
if len(args) == 0 {
root, err = os.Getwd()
if len(args) <= 0 {
wd, err := os.Getwd()
if err != nil {
return errors.Wrap(err, "os.Getwd")
return err
}
root = wd
} else {
root = args[0]
}
Expand All @@ -69,7 +64,7 @@ func runInit(args []string) error {
return err
}
if mok {
return fmt.Errorf("Manifest file %q already exists", mf)
return fmt.Errorf("manifest file %q already exists", mf)
}
// Manifest file does not exist.

Expand Down
Loading