Repository: caddyserver/caddy
File: caddy.go (Go)

Code before:
			if err != nil {
				// an app failed to start, so we need to stop
				// all other apps that were already started
				for _, otherAppName := range started {
					err2 := ctx.cfg.apps[otherAppName].Stop()
					if err2 != nil {
						err = fmt.Errorf("%v; additionally, aborting app %s: %v",
							err, otherAppName, err2)
					}
				}
				return fmt.Errorf("%s app module: start: %v", name, err)
			}
			started = append(started, name)
		}
		return nil
	}()
	if err != nil {
		return ctx, err
	}

	// now that the user's config is running, finish setting up anything else,
	// such as remote admin endpoint, config loader, etc.
	return ctx, finishSettingUp(ctx, ctx.cfg)
}

func BuildContext(newCfg *Config, replaceAdminServer bool) (Context, error) {
	// because we will need to roll back any state
	// modifications if this function errors, we
	// keep a single error value and scope all
	// sub-operations to their own functions to
	// ensure this error value does not get
	// overridden or missed when it should have
	// been set by a short assignment
	var err error

	if newCfg == nil {
		newCfg = new(Config)
	}

	// create a context within which to load
	// modules - essentially our new config's
	// execution environment; be sure that
	// cleanup occurs when we return if there
	// was an error; if no error, it will get
	// cleaned up on next config cycle
	ctx, cancel := NewContext(Context{Context: context.Background(), cfg: newCfg})
	defer func() {
		if err != nil {
			// if there were any errors during startup,
			// we should cancel the new context we created
			// since the associated config won't be used;

Review comment (suggestion):
Discussed with @mholt: Going to rename to `ProvisionContext` to better capture intent and match the existing code. 

Docs will come then, too. 

Code after:
			if err != nil {
				// an app failed to start, so we need to stop
				// all other apps that were already started
				for _, otherAppName := range started {
					err2 := ctx.cfg.apps[otherAppName].Stop()
					if err2 != nil {
						err = fmt.Errorf("%v; additionally, aborting app %s: %v",
							err, otherAppName, err2)
					}
				}
				return fmt.Errorf("%s app module: start: %v", name, err)
			}
			started = append(started, name)
		}
		return nil
	}()
	if err != nil {
		return ctx, err
	}

	// now that the user's config is running, finish setting up anything else,
	// such as remote admin endpoint, config loader, etc.
	return ctx, finishSettingUp(ctx, ctx.cfg)
}

// provisionContext creates a new context from the given configuration and provisions
// storage and apps.
// If `newCfg` is nil a new empty configuration will be created.
// If `replaceAdminServer` is true any currently active admin server will be replaced
// with a new admin server based on the provided configuration.
func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error) {
	// because we will need to roll back any state
	// modifications if this function errors, we
	// keep a single error value and scope all
	// sub-operations to their own functions to
	// ensure this error value does not get
	// overridden or missed when it should have
	// been set by a short assignment
	var err error

	if newCfg == nil {
		newCfg = new(Config)
	}

	// create a context within which to load
	// modules - essentially our new config's
	// execution environment; be sure that
	// cleanup occurs when we return if there
	// was an error; if no error, it will get
	// cleaned up on next config cycle
	ctx, cancel := NewContext(Context{Context: context.Background(), cfg: newCfg})