// Remove removes published repository, cleaning up directories, files
func (collection *PublishedRepoCollection) Remove(publishedStorageProvider aptly.PublishedStorageProvider,
	storage, prefix, distribution string, collectionFactory *CollectionFactory, progress aptly.Progress) error {
	repo, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		return err
	}

	removePrefix := true
	removePoolComponents := repo.Components()
	cleanComponents := []string{}
	repoPosition := -1

	for i, r := range collection.list {
		if r == repo {
			repoPosition = i
			continue
		}
		if r.Storage == repo.Storage && r.Prefix == repo.Prefix {
			removePrefix = false

			rComponents := r.Components()
			for _, component := range rComponents {
				if utils.StrSliceHasItem(removePoolComponents, component) {
					removePoolComponents = utils.StrSlicesSubstract(removePoolComponents, []string{component})
					cleanComponents = append(cleanComponents, component)
				}
			}
		}
	}

	err = repo.RemoveFiles(publishedStorageProvider, removePrefix, removePoolComponents, progress)
	if err != nil {
		return err
	}

	collection.list[len(collection.list)-1], collection.list[repoPosition], collection.list =
		nil, collection.list[len(collection.list)-1], collection.list[:len(collection.list)-1]

	if len(cleanComponents) > 0 {
		err = collection.CleanupPrefixComponentFiles(repo.Prefix, cleanComponents,
			publishedStorageProvider.GetPublishedStorage(storage), collectionFactory, progress)
		if err != nil {
			return err
		}
	}

	err = collection.db.Delete(repo.Key())
	if err != nil {
		return err
	}

	for _, component := range repo.Components() {
		err = collection.db.Delete(repo.RefKey(component))
		if err != nil {
			return err
		}
	}

	return nil
}
// BySnapshotSource looks up snapshots that have specified snapshot as a source
func (collection *SnapshotCollection) BySnapshotSource(snapshot *Snapshot) []*Snapshot {
	result := make([]*Snapshot, 0)

	for _, s := range collection.list {
		if s.SourceKind == "snapshot" && utils.StrSliceHasItem(s.SourceIDs, snapshot.UUID) {
			result = append(result, s)
		}
	}
	return result
}
// ByLocalRepoSource looks up snapshots that have specified LocalRepo as a source
func (collection *SnapshotCollection) ByLocalRepoSource(repo *LocalRepo) []*Snapshot {
	result := make([]*Snapshot, 0)

	for _, s := range collection.list {
		if s.SourceKind == "local" && utils.StrSliceHasItem(s.SourceIDs, repo.UUID) {
			result = append(result, s)
		}
	}
	return result
}
Exemple #4
0
func (u *Uploaders) expandGroupsInternal(items []string, trail []string) []string {
	result := []string{}

	for _, item := range items {
		// stop infinite recursion
		if utils.StrSliceHasItem(trail, item) {
			continue
		}

		group, ok := u.Groups[item]
		if !ok {
			result = append(result, item)
		} else {
			newTrail := append([]string(nil), trail...)
			result = append(result, u.expandGroupsInternal(group, append(newTrail, item))...)
		}
	}

	return result
}
Exemple #5
0
// MatchesDependency checks whether package matches specified dependency
func (p *Package) MatchesDependency(dep Dependency) bool {
	if dep.Architecture != "" && !p.MatchesArchitecture(dep.Architecture) {
		return false
	}

	if dep.Relation == VersionDontCare {
		if utils.StrSliceHasItem(p.Provides, dep.Pkg) {
			return true
		}
		return dep.Pkg == p.Name
	}

	if dep.Pkg != p.Name {
		return false
	}

	r := CompareVersions(p.Version, dep.Version)

	switch dep.Relation {
	case VersionEqual:
		return r == 0
	case VersionLess:
		return r < 0
	case VersionGreater:
		return r > 0
	case VersionLessOrEqual:
		return r <= 0
	case VersionGreaterOrEqual:
		return r >= 0
	case VersionPatternMatch:
		matched, err := filepath.Match(dep.Version, p.Version)
		return err == nil && matched
	case VersionRegexp:
		return dep.Regexp.FindStringIndex(p.Version) != nil
	}

	panic("unknown relation")
}
Exemple #6
0
// WriteTo dumps sorted mapping of files to qualified package names
func (index *ContentsIndex) WriteTo(w io.Writer) (int64, error) {
	var n int64

	paths := make([]string, len(index.index))

	i := 0
	for path := range index.index {
		paths[i] = path
		i++
	}

	sort.Strings(paths)

	nn, err := fmt.Fprintf(w, "%s %s\n", "FILE", "LOCATION")
	n += int64(nn)
	if err != nil {
		return n, err
	}

	for _, path := range paths {
		packages := index.index[path]
		parts := make([]string, 0, len(packages))
		for i := range packages {
			name := packages[i].QualifiedName()
			if !utils.StrSliceHasItem(parts, name) {
				parts = append(parts, name)
			}
		}
		nn, err = fmt.Fprintf(w, "%s %s\n", path, strings.Join(parts, ","))
		n += int64(nn)
		if err != nil {
			return n, err
		}
	}

	return n, nil
}
Exemple #7
0
func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
	var err error

	components := strings.Split(context.Flags().Lookup("component").Value.String(), ",")

	if len(args) < len(components) || len(args) > len(components)+1 {
		cmd.Usage()
		return commander.ErrCommandError
	}

	var param string
	if len(args) == len(components)+1 {
		param = args[len(components)]
		args = args[0 : len(args)-1]
	} else {
		param = ""
	}
	storage, prefix := deb.ParsePrefix(param)

	var (
		sources = []interface{}{}
		message string
	)

	if cmd.Name() == "snapshot" {
		var (
			snapshot     *deb.Snapshot
			emptyWarning = false
			parts        = []string{}
		)

		for _, name := range args {
			snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(name)
			if err != nil {
				return fmt.Errorf("unable to publish: %s", err)
			}

			err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
			if err != nil {
				return fmt.Errorf("unable to publish: %s", err)
			}

			sources = append(sources, snapshot)
			parts = append(parts, snapshot.Name)

			if snapshot.NumPackages() == 0 {
				emptyWarning = true
			}
		}

		if len(parts) == 1 {
			message = fmt.Sprintf("Snapshot %s has", parts[0])
		} else {
			message = fmt.Sprintf("Snapshots %s have", strings.Join(parts, ", "))

		}

		if emptyWarning {
			context.Progress().Printf("Warning: publishing from empty source, architectures list should be complete, it can't be changed after publishing (use -architectures flag)\n")
		}
	} else if cmd.Name() == "repo" {
		var (
			localRepo    *deb.LocalRepo
			emptyWarning = false
			parts        = []string{}
		)

		for _, name := range args {
			localRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(name)
			if err != nil {
				return fmt.Errorf("unable to publish: %s", err)
			}

			err = context.CollectionFactory().LocalRepoCollection().LoadComplete(localRepo)
			if err != nil {
				return fmt.Errorf("unable to publish: %s", err)
			}

			sources = append(sources, localRepo)
			parts = append(parts, localRepo.Name)

			if localRepo.NumPackages() == 0 {
				emptyWarning = true
			}
		}

		if len(parts) == 1 {
			message = fmt.Sprintf("Local repo %s has", parts[0])
		} else {
			message = fmt.Sprintf("Local repos %s have", strings.Join(parts, ", "))

		}

		if emptyWarning {
			context.Progress().Printf("Warning: publishing from empty source, architectures list should be complete, it can't be changed after publishing (use -architectures flag)\n")
		}
	} else {
		panic("unknown command")
	}

	distribution := context.Flags().Lookup("distribution").Value.String()

	published, err := deb.NewPublishedRepo(storage, prefix, distribution, context.ArchitecturesList(), components, sources, context.CollectionFactory())
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}
	published.Origin = context.Flags().Lookup("origin").Value.String()
	published.Label = context.Flags().Lookup("label").Value.String()

	if context.Flags().IsSet("skip-contents") {
		published.SkipContents = context.Flags().Lookup("skip-contents").Value.Get().(bool)
	}

	duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published)
	if duplicate != nil {
		context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
		return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
	}

	signer, err := getSigner(context.Flags())
	if err != nil {
		return fmt.Errorf("unable to initialize GPG signer: %s", err)
	}

	forceOverwrite := context.Flags().Lookup("force-overwrite").Value.Get().(bool)
	if forceOverwrite {
		context.Progress().ColoredPrintf("@rWARNING@|: force overwrite mode enabled, aptly might corrupt other published repositories sharing " +
			"the same package pool.\n")
	}

	err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, context.Progress(), forceOverwrite)
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	err = context.CollectionFactory().PublishedRepoCollection().Add(published)
	if err != nil {
		return fmt.Errorf("unable to save to DB: %s", err)
	}

	var repoComponents string
	prefix, repoComponents, distribution = published.Prefix, strings.Join(published.Components(), " "), published.Distribution
	if prefix == "." {
		prefix = ""
	} else if !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	context.Progress().Printf("\n%s been successfully published.\n", message)

	if localStorage, ok := context.GetPublishedStorage(storage).(aptly.LocalPublishedStorage); ok {
		context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n",
			localStorage.PublicPath())
	}

	context.Progress().Printf("Now you can add following line to apt sources:\n")
	context.Progress().Printf("  deb http://your-server/%s %s %s\n", prefix, distribution, repoComponents)
	if utils.StrSliceHasItem(published.Architectures, "source") {
		context.Progress().Printf("  deb-src http://your-server/%s %s %s\n", prefix, distribution, repoComponents)
	}
	context.Progress().Printf("Don't forget to add your GPG key to apt with apt-key.\n")
	context.Progress().Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")

	return err
}
Exemple #8
0
// CleanupPrefixComponentFiles removes all unreferenced files in published storage under prefix/component pair
func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(prefix string, components []string,
	publishedStorage aptly.PublishedStorage, collectionFactory *CollectionFactory, progress aptly.Progress) error {

	var err error
	referencedFiles := map[string][]string{}

	if progress != nil {
		progress.Printf("Cleaning up prefix %#v components %s...\n", prefix, strings.Join(components, ", "))
	}

	for _, r := range collection.list {
		if r.Prefix == prefix {
			matches := false

			repoComponents := r.Components()

			for _, component := range components {
				if utils.StrSliceHasItem(repoComponents, component) {
					matches = true
					break
				}
			}

			if !matches {
				continue
			}

			err = collection.LoadComplete(r, collectionFactory)
			if err != nil {
				return err
			}

			for _, component := range components {
				if utils.StrSliceHasItem(repoComponents, component) {
					packageList, err := NewPackageListFromRefList(r.RefList(component), collectionFactory.PackageCollection(), progress)
					if err != nil {
						return err
					}

					packageList.ForEach(func(p *Package) error {
						poolDir, err := p.PoolDirectory()
						if err != nil {
							return err
						}

						for _, f := range p.Files() {
							referencedFiles[component] = append(referencedFiles[component], filepath.Join(poolDir, f.Filename))
						}

						return nil
					})
				}
			}
		}
	}

	for _, component := range components {
		sort.Strings(referencedFiles[component])

		rootPath := filepath.Join(prefix, "pool", component)
		existingFiles, err := publishedStorage.Filelist(rootPath)
		if err != nil {
			return err
		}

		sort.Strings(existingFiles)

		filesToDelete := utils.StrSlicesSubstract(existingFiles, referencedFiles[component])

		for _, file := range filesToDelete {
			err = publishedStorage.Remove(filepath.Join(rootPath, file))
			if err != nil {
				return err
			}
		}
	}

	return nil
}
// Architectures returns list of architectures present in packages and flag if source packages are present.
//
// If includeSource is true, meta-architecture "source" would be present in the list
func (l *PackageList) Architectures(includeSource bool) (result []string) {
	result = make([]string, 0, 10)
	for _, pkg := range l.packages {
		if pkg.Architecture != "all" && (pkg.Architecture != "source" || includeSource) && !utils.StrSliceHasItem(result, pkg.Architecture) {
			result = append(result, pkg.Architecture)
		}
	}
	return
}
Exemple #10
0
func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error {
	var err error
	if len(args) < 1 || len(args) > 2 {
		cmd.Usage()
		return err
	}

	name := args[0]

	var prefix string
	if len(args) == 2 {
		prefix = args[1]
	} else {
		prefix = ""
	}

	var (
		source  interface{}
		message string
	)

	if cmd.Name() == "snapshot" {
		var snapshot *deb.Snapshot
		snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(name)
		if err != nil {
			return fmt.Errorf("unable to publish: %s", err)
		}

		err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
		if err != nil {
			return fmt.Errorf("unable to publish: %s", err)
		}

		source = snapshot
		message = fmt.Sprintf("Snapshot %s", snapshot.Name)
	} else if cmd.Name() == "repo" {
		var localRepo *deb.LocalRepo
		localRepo, err = context.CollectionFactory().LocalRepoCollection().ByName(name)
		if err != nil {
			return fmt.Errorf("unable to publish: %s", err)
		}

		err = context.CollectionFactory().LocalRepoCollection().LoadComplete(localRepo)
		if err != nil {
			return fmt.Errorf("unable to publish: %s", err)
		}

		source = localRepo
		message = fmt.Sprintf("Local repo %s", localRepo.Name)
	} else {
		panic("unknown command")
	}

	component := context.flags.Lookup("component").Value.String()
	distribution := context.flags.Lookup("distribution").Value.String()

	published, err := deb.NewPublishedRepo(prefix, distribution, component, context.ArchitecturesList(), source, context.CollectionFactory())
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}
	published.Origin = cmd.Flag.Lookup("origin").Value.String()
	published.Label = cmd.Flag.Lookup("label").Value.String()

	duplicate := context.CollectionFactory().PublishedRepoCollection().CheckDuplicate(published)
	if duplicate != nil {
		context.CollectionFactory().PublishedRepoCollection().LoadComplete(duplicate, context.CollectionFactory())
		return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
	}

	signer, err := getSigner(context.flags)
	if err != nil {
		return fmt.Errorf("unable to initialize GPG signer: %s", err)
	}

	err = published.Publish(context.PackagePool(), context.PublishedStorage(), context.CollectionFactory(), signer, context.Progress())
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	err = context.CollectionFactory().PublishedRepoCollection().Add(published)
	if err != nil {
		return fmt.Errorf("unable to save to DB: %s", err)
	}

	prefix, component, distribution = published.Prefix, published.Component, published.Distribution
	if prefix == "." {
		prefix = ""
	} else if !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	context.Progress().Printf("\n%s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n",
		message, context.PublishedStorage().PublicPath())
	context.Progress().Printf("Now you can add following line to apt sources:\n")
	context.Progress().Printf("  deb http://your-server/%s %s %s\n", prefix, distribution, component)
	if utils.StrSliceHasItem(published.Architectures, "source") {
		context.Progress().Printf("  deb-src http://your-server/%s %s %s\n", prefix, distribution, component)
	}
	context.Progress().Printf("Don't forget to add your GPG key to apt with apt-key.\n")
	context.Progress().Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")

	return err
}
Exemple #11
0
func aptlyServe(cmd *commander.Command, args []string) error {
	var err error

	if len(args) != 0 {
		cmd.Usage()
		return commander.ErrCommandError
	}

	if context.CollectionFactory().PublishedRepoCollection().Len() == 0 {
		fmt.Printf("No published repositories, unable to serve.\n")
		return nil
	}

	listen := context.Flags().Lookup("listen").Value.String()

	listenHost, listenPort, err := net.SplitHostPort(listen)

	if err != nil {
		return fmt.Errorf("wrong -listen specification: %s", err)
	}

	if listenHost == "" {
		listenHost, err = os.Hostname()
		if err != nil {
			listenHost = "localhost"
		}
	}

	fmt.Printf("Serving published repositories, recommended apt sources list:\n\n")

	sources := make(sort.StringSlice, 0, context.CollectionFactory().PublishedRepoCollection().Len())
	published := make(map[string]*deb.PublishedRepo, context.CollectionFactory().PublishedRepoCollection().Len())

	err = context.CollectionFactory().PublishedRepoCollection().ForEach(func(repo *deb.PublishedRepo) error {
		err := context.CollectionFactory().PublishedRepoCollection().LoadComplete(repo, context.CollectionFactory())
		if err != nil {
			return err
		}

		sources = append(sources, repo.String())
		published[repo.String()] = repo

		return nil
	})

	if err != nil {
		return fmt.Errorf("unable to serve: %s", err)
	}

	sort.Strings(sources)

	for _, source := range sources {
		repo := published[source]

		prefix := repo.Prefix
		if prefix == "." {
			prefix = ""
		} else {
			prefix += "/"
		}

		fmt.Printf("# %s\ndeb http://%s:%s/%s %s %s\n",
			repo, listenHost, listenPort, prefix, repo.Distribution, strings.Join(repo.Components(), " "))

		if utils.StrSliceHasItem(repo.Architectures, "source") {
			fmt.Printf("deb-src http://%s:%s/%s %s %s\n",
				listenHost, listenPort, prefix, repo.Distribution, strings.Join(repo.Components(), " "))
		}
	}

	publicPath := context.GetPublishedStorage("").(aptly.LocalPublishedStorage).PublicPath()
	ShutdownContext()

	fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)

	err = http.ListenAndServe(listen, http.FileServer(http.Dir(publicPath)))
	if err != nil {
		return fmt.Errorf("unable to serve: %s", err)
	}
	return nil
}
Exemple #12
0
func (a *Api) PublishSwitch(prefix, distribution string, snapshots []PublishSource,
	forceOverwrite bool, signingOptions SigningOptions) (*deb.PublishedRepo, error) {

	param := parseEscapedPath(prefix)
	storage, prefix := deb.ParsePrefix(param)
	signer, err := getSigner(&signingOptions)
	if err != nil {
		return nil, fmt.Errorf("unable to initialize GPG signer: %s", err)
	}

	// published.LoadComplete would touch local repo collection
	localRepoCollection := a.Ctx().CollectionFactory().LocalRepoCollection()
	localRepoCollection.RLock()
	defer localRepoCollection.RUnlock()

	snapshotCollection := a.Ctx().CollectionFactory().SnapshotCollection()
	snapshotCollection.RLock()
	defer snapshotCollection.RUnlock()

	collection := a.Ctx().CollectionFactory().PublishedRepoCollection()
	collection.Lock()
	defer collection.Unlock()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		return nil, fmt.Errorf("unable to update: %s", err)
	}
	err = collection.LoadComplete(published, a.Ctx().CollectionFactory())
	if err != nil {
		return nil, fmt.Errorf("unable to update: %s", err)
	}

	var updatedComponents []string

	if published.SourceKind == "local" {
		if len(snapshots) > 0 {
			return nil, fmt.Errorf("snapshots shouldn't be given when updating local repo")
		}
		updatedComponents = published.Components()
		for _, component := range updatedComponents {
			published.UpdateLocalRepo(component)
		}
	} else if published.SourceKind == "snapshot" {
		publishedComponents := published.Components()
		for _, snapshotInfo := range snapshots {
			if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
				return nil, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component)
			}

			snapshot, err := snapshotCollection.ByName(snapshotInfo.Name)
			if err != nil {
				return nil, err
			}

			err = snapshotCollection.LoadComplete(snapshot)
			if err != nil {
				return nil, err
			}

			published.UpdateSnapshot(snapshotInfo.Component, snapshot)
			updatedComponents = append(updatedComponents, snapshotInfo.Component)
		}
	} else {
		return nil, fmt.Errorf("unknown published repository type")
	}

	err = published.Publish(a.Ctx().PackagePool(), a.Ctx(), a.Ctx().CollectionFactory(), signer, nil, forceOverwrite)
	if err != nil {
		return nil, fmt.Errorf("unable to update: %s", err)
	}

	err = collection.Update(published)
	if err != nil {
		return nil, fmt.Errorf("unable to save to DB: %s", err)
	}

	err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
		a.Ctx().GetPublishedStorage(storage), a.Ctx().CollectionFactory(), nil)
	if err != nil {
		return nil, fmt.Errorf("unable to update: %s", err)
	}

	return published, nil
}
Exemple #13
0
func aptlyServe(cmd *commander.Command, args []string) error {
	var err error

	publishedCollection := debian.NewPublishedRepoCollection(context.database)
	snapshotCollection := debian.NewSnapshotCollection(context.database)

	if publishedCollection.Len() == 0 {
		fmt.Printf("No published repositories, unable to serve.\n")
		return nil
	}

	listen := cmd.Flag.Lookup("listen").Value.String()

	listenHost, listenPort, err := net.SplitHostPort(listen)

	if err != nil {
		return fmt.Errorf("wrong -listen specification: %s", err)
	}

	if listenHost == "" {
		listenHost, err = os.Hostname()
		if err != nil {
			listenHost = "localhost"
		}
	}

	fmt.Printf("Serving published repositories, recommended apt sources list:\n\n")

	sources := make(sort.StringSlice, 0, publishedCollection.Len())
	published := make(map[string]*debian.PublishedRepo, publishedCollection.Len())

	err = publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
		err := publishedCollection.LoadComplete(repo, snapshotCollection)
		if err != nil {
			return err
		}

		sources = append(sources, repo.String())
		published[repo.String()] = repo

		return nil
	})

	if err != nil {
		return fmt.Errorf("unable to serve: %s", err)
	}

	sort.Strings(sources)

	for _, source := range sources {
		repo := published[source]

		prefix := repo.Prefix
		if prefix == "." {
			prefix = ""
		} else {
			prefix += "/"
		}

		fmt.Printf("# %s\ndeb http://%s:%s/%s %s %s\n",
			repo, listenHost, listenPort, prefix, repo.Distribution, repo.Component)

		if utils.StrSliceHasItem(repo.Architectures, "source") {
			fmt.Printf("deb-src http://%s:%s/%s %s %s\n",
				listenHost, listenPort, prefix, repo.Distribution, repo.Component)
		}
	}

	context.database.Close()

	fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)

	err = http.ListenAndServe(listen, http.FileServer(http.Dir(context.packageRepository.PublicPath())))
	if err != nil {
		return fmt.Errorf("unable to serve: %s", err)
	}
	return nil
}
Exemple #14
0
// PUT /publish/:prefix/:distribution
func apiPublishUpdateSwitch(c *gin.Context) {
	param := parseEscapedPath(c.Params.ByName("prefix"))
	storage, prefix := deb.ParsePrefix(param)
	distribution := c.Params.ByName("distribution")

	var b struct {
		ForceOverwrite bool
		Signing        SigningOptions
		SkipContents   *bool
		Snapshots      []struct {
			Component string `binding:"required"`
			Name      string `binding:"required"`
		}
	}

	if !c.Bind(&b) {
		return
	}

	signer, err := getSigner(&b.Signing)
	if err != nil {
		c.Fail(500, fmt.Errorf("unable to initialize GPG signer: %s", err))
		return
	}

	// published.LoadComplete would touch local repo collection
	localRepoCollection := context.CollectionFactory().LocalRepoCollection()
	localRepoCollection.RLock()
	defer localRepoCollection.RUnlock()

	snapshotCollection := context.CollectionFactory().SnapshotCollection()
	snapshotCollection.RLock()
	defer snapshotCollection.RUnlock()

	collection := context.CollectionFactory().PublishedRepoCollection()
	collection.Lock()
	defer collection.Unlock()

	published, err := collection.ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		c.Fail(404, fmt.Errorf("unable to update: %s", err))
		return
	}
	err = collection.LoadComplete(published, context.CollectionFactory())
	if err != nil {
		c.Fail(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	var updatedComponents []string

	if published.SourceKind == "local" {
		if len(b.Snapshots) > 0 {
			c.Fail(400, fmt.Errorf("snapshots shouldn't be given when updating local repo"))
			return
		}
		updatedComponents = published.Components()
		for _, component := range updatedComponents {
			published.UpdateLocalRepo(component)
		}
	} else if published.SourceKind == "snapshot" {
		publishedComponents := published.Components()
		for _, snapshotInfo := range b.Snapshots {
			if !utils.StrSliceHasItem(publishedComponents, snapshotInfo.Component) {
				c.Fail(404, fmt.Errorf("component %s is not in published repository", snapshotInfo.Component))
				return
			}

			snapshot, err := snapshotCollection.ByName(snapshotInfo.Name)
			if err != nil {
				c.Fail(404, err)
				return
			}

			err = snapshotCollection.LoadComplete(snapshot)
			if err != nil {
				c.Fail(500, err)
				return
			}

			published.UpdateSnapshot(snapshotInfo.Component, snapshot)
			updatedComponents = append(updatedComponents, snapshotInfo.Component)
		}
	} else {
		c.Fail(500, fmt.Errorf("unknown published repository type"))
		return
	}

	if b.SkipContents != nil {
		published.SkipContents = *b.SkipContents
	}

	err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, nil, b.ForceOverwrite)
	if err != nil {
		c.Fail(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	err = collection.Update(published)
	if err != nil {
		c.Fail(500, fmt.Errorf("unable to save to DB: %s", err))
		return
	}

	err = collection.CleanupPrefixComponentFiles(published.Prefix, updatedComponents,
		context.GetPublishedStorage(storage), context.CollectionFactory(), nil)
	if err != nil {
		c.Fail(500, fmt.Errorf("unable to update: %s", err))
		return
	}

	c.JSON(200, published)
}
Exemple #15
0
func aptlyPublishSwitch(cmd *commander.Command, args []string) error {
	var err error

	components := strings.Split(context.Flags().Lookup("component").Value.String(), ",")

	if len(args) < len(components)+1 || len(args) > len(components)+2 {
		cmd.Usage()
		return commander.ErrCommandError
	}

	distribution := args[0]
	param := "."

	var (
		names    []string
		snapshot *deb.Snapshot
	)

	if len(args) == len(components)+2 {
		param = args[1]
		names = args[2:]
	} else {
		names = args[1:]
	}

	storage, prefix := deb.ParsePrefix(param)

	var published *deb.PublishedRepo

	published, err = context.CollectionFactory().PublishedRepoCollection().ByStoragePrefixDistribution(storage, prefix, distribution)
	if err != nil {
		return fmt.Errorf("unable to update: %s", err)
	}

	if published.SourceKind != "snapshot" {
		return fmt.Errorf("unable to update: not a snapshot publish")
	}

	err = context.CollectionFactory().PublishedRepoCollection().LoadComplete(published, context.CollectionFactory())
	if err != nil {
		return fmt.Errorf("unable to update: %s", err)
	}

	publishedComponents := published.Components()
	if len(components) == 1 && len(publishedComponents) == 1 && components[0] == "" {
		components = publishedComponents
	}

	if len(names) != len(components) {
		return fmt.Errorf("mismatch in number of components (%d) and snapshots (%d)", len(components), len(names))
	}

	for i, component := range components {
		if !utils.StrSliceHasItem(publishedComponents, component) {
			return fmt.Errorf("unable to switch: component %s is not in published repository", component)
		}

		snapshot, err = context.CollectionFactory().SnapshotCollection().ByName(names[i])
		if err != nil {
			return fmt.Errorf("unable to switch: %s", err)
		}

		err = context.CollectionFactory().SnapshotCollection().LoadComplete(snapshot)
		if err != nil {
			return fmt.Errorf("unable to switch: %s", err)
		}

		published.UpdateSnapshot(component, snapshot)
	}

	signer, err := getSigner(context.Flags())
	if err != nil {
		return fmt.Errorf("unable to initialize GPG signer: %s", err)
	}

	forceOverwrite := context.Flags().Lookup("force-overwrite").Value.Get().(bool)
	if forceOverwrite {
		context.Progress().ColoredPrintf("@rWARNING@|: force overwrite mode enabled, aptly might corrupt other published repositories sharing " +
			"the same package pool.\n")
	}

	if context.Flags().IsSet("skip-contents") {
		published.SkipContents = context.Flags().Lookup("skip-contents").Value.Get().(bool)
	}

	err = published.Publish(context.PackagePool(), context, context.CollectionFactory(), signer, context.Progress(), forceOverwrite)
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	err = context.CollectionFactory().PublishedRepoCollection().Update(published)
	if err != nil {
		return fmt.Errorf("unable to save to DB: %s", err)
	}

	err = context.CollectionFactory().PublishedRepoCollection().CleanupPrefixComponentFiles(published.Prefix, components,
		context.GetPublishedStorage(storage), context.CollectionFactory(), context.Progress())
	if err != nil {
		return fmt.Errorf("unable to update: %s", err)
	}

	context.Progress().Printf("\nPublish for snapshot %s has been successfully switched to new snapshot.\n", published.String())

	return err
}
Exemple #16
0
func aptlyPublishSnapshot(cmd *commander.Command, args []string) error {
	var err error
	if len(args) < 1 || len(args) > 2 {
		cmd.Usage()
		return err
	}

	name := args[0]

	var prefix string
	if len(args) == 2 {
		prefix = args[1]
	} else {
		prefix = ""
	}

	publishedCollecton := debian.NewPublishedRepoCollection(context.database)

	snapshotCollection := debian.NewSnapshotCollection(context.database)
	snapshot, err := snapshotCollection.ByName(name)
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	err = snapshotCollection.LoadComplete(snapshot)
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	var sourceRepo *debian.RemoteRepo

	if snapshot.SourceKind == "repo" && len(snapshot.SourceIDs) == 1 {
		repoCollection := debian.NewRemoteRepoCollection(context.database)

		sourceRepo, _ = repoCollection.ByUUID(snapshot.SourceIDs[0])
	}

	component := cmd.Flag.Lookup("component").Value.String()
	if component == "" {
		if sourceRepo != nil && len(sourceRepo.Components) == 1 {
			component = sourceRepo.Components[0]
		} else {
			component = "main"
		}
	}

	distribution := cmd.Flag.Lookup("distribution").Value.String()
	if distribution == "" {
		if sourceRepo != nil {
			distribution = sourceRepo.Distribution
		}

		if distribution == "" {
			return fmt.Errorf("unable to guess distribution name, please specify explicitly")
		}
	}

	published, err := debian.NewPublishedRepo(prefix, distribution, component, context.architecturesList, snapshot)
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	duplicate := publishedCollecton.CheckDuplicate(published)
	if duplicate != nil {
		publishedCollecton.LoadComplete(duplicate, snapshotCollection)
		return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate)
	}

	signer, err := getSigner(cmd)
	if err != nil {
		return fmt.Errorf("unable to initialize GPG signer: %s", err)
	}

	packageCollection := debian.NewPackageCollection(context.database)
	err = published.Publish(context.packagePool, context.publishedStorage, packageCollection, signer)
	if err != nil {
		return fmt.Errorf("unable to publish: %s", err)
	}

	err = publishedCollecton.Add(published)
	if err != nil {
		return fmt.Errorf("unable to save to DB: %s", err)
	}

	if prefix != "" && !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	fmt.Printf("\nSnapshot %s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n",
		snapshot.Name, context.publishedStorage.PublicPath())
	fmt.Printf("Now you can add following line to apt sources:\n")
	fmt.Printf("  deb http://your-server/%s %s %s\n", prefix, distribution, component)
	if utils.StrSliceHasItem(published.Architectures, "source") {
		fmt.Printf("  deb-src http://your-server/%s %s %s\n", prefix, distribution, component)
	}
	fmt.Printf("Don't forget to add your GPG key to apt with apt-key.\n")
	fmt.Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n")

	return err
}