managers.GoDep.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of analyzer Show documentation
Show all versions of analyzer Show documentation
Part of the OSS Review Toolkit (ORT), a suite to automate software compliance checks.
/*
* Copyright (C) 2017 The ORT Project Authors (see )
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/
package org.ossreviewtoolkit.analyzer.managers
import com.moandjiezana.toml.Toml
import java.io.File
import java.io.IOException
import java.net.URI
import kotlin.io.path.copyToRecursively
import kotlin.io.path.createDirectories
import org.apache.logging.log4j.kotlin.Logging
import org.ossreviewtoolkit.analyzer.AbstractPackageManagerFactory
import org.ossreviewtoolkit.analyzer.PackageManager
import org.ossreviewtoolkit.analyzer.managers.utils.normalizeModuleVersion
import org.ossreviewtoolkit.downloader.VcsHost
import org.ossreviewtoolkit.downloader.VersionControlSystem
import org.ossreviewtoolkit.model.Identifier
import org.ossreviewtoolkit.model.Issue
import org.ossreviewtoolkit.model.Package
import org.ossreviewtoolkit.model.PackageLinkage
import org.ossreviewtoolkit.model.PackageReference
import org.ossreviewtoolkit.model.Project
import org.ossreviewtoolkit.model.ProjectAnalyzerResult
import org.ossreviewtoolkit.model.RemoteArtifact
import org.ossreviewtoolkit.model.Scope
import org.ossreviewtoolkit.model.VcsInfo
import org.ossreviewtoolkit.model.VcsType
import org.ossreviewtoolkit.model.config.AnalyzerConfiguration
import org.ossreviewtoolkit.model.config.RepositoryConfiguration
import org.ossreviewtoolkit.model.createAndLogIssue
import org.ossreviewtoolkit.model.orEmpty
import org.ossreviewtoolkit.utils.common.CommandLineTool
import org.ossreviewtoolkit.utils.common.ProcessCapture
import org.ossreviewtoolkit.utils.common.collectMessages
import org.ossreviewtoolkit.utils.common.realFile
import org.ossreviewtoolkit.utils.common.safeDeleteRecursively
import org.ossreviewtoolkit.utils.common.toUri
import org.ossreviewtoolkit.utils.ort.createOrtTempDir
import org.ossreviewtoolkit.utils.ort.showStackTrace
/**
* A map of legacy package manager file names "dep" can import, and their respective lock file names, if any.
*/
private val GO_LEGACY_MANIFESTS = mapOf(
// The [Glide](https://github.com/Masterminds/glide) package manager uses a dedicated `glide.yaml` rules file for
// direct dependencies and scans dependent packages for imports to determine transitive dependencies.
"glide.yaml" to "glide.lock",
// The [godep](https://github.com/tools/godep) dependency manager works by inspecting imports but was discontinued
// in favor of the [dep](https://github.com/golang/dep) dependency management tool.
"Godeps.json" to ""
)
/**
* The [Dep](https://golang.github.io/dep/) package manager for Go.
*
* Note: Dep was an official experiment to implement a package manager for Go. As of 2020, Dep is deprecated and
* archived in favor of Go modules, which have had official support since Go 1.11.
*/
class GoDep(
name: String,
analysisRoot: File,
analyzerConfig: AnalyzerConfiguration,
repoConfig: RepositoryConfiguration
) : PackageManager(name, analysisRoot, analyzerConfig, repoConfig), CommandLineTool {
private companion object : Logging
class Factory : AbstractPackageManagerFactory("GoDep") {
override val globsForDefinitionFiles = listOf("Gopkg.toml", *GO_LEGACY_MANIFESTS.keys.toTypedArray())
override fun create(
analysisRoot: File,
analyzerConfig: AnalyzerConfiguration,
repoConfig: RepositoryConfiguration
) = GoDep(type, analysisRoot, analyzerConfig, repoConfig)
}
override fun command(workingDir: File?) = "dep"
override fun getVersionArguments() = "version"
override fun transformVersion(output: String) =
output.lineSequence().first { "version" in it }.substringAfter(':').trim().removePrefix("v")
override fun resolveDependencies(definitionFile: File, labels: Map): List {
val projectDir = resolveProjectRoot(definitionFile)
val projectVcs = processProjectVcs(projectDir)
val gopath = createOrtTempDir("${projectDir.name}-gopath")
val workingDir = setUpWorkspace(projectDir, projectVcs, gopath)
GO_LEGACY_MANIFESTS[definitionFile.name]?.let { lockfileName ->
logger.debug { "Importing legacy manifest file at '$definitionFile'." }
importLegacyManifest(lockfileName, workingDir, gopath)
}
val projects = parseProjects(workingDir, gopath)
val packages = mutableSetOf()
val packageRefs = mutableSetOf()
for (project in projects) {
// parseProjects() made sure that all entries contain these keys
val name = project.getValue("name")
val revision = project.getValue("revision")
val version = project.getValue("version")
val issues = mutableListOf()
val vcsProcessed = try {
resolveVcsInfo(name, revision, gopath)
} catch (e: IOException) {
e.showStackTrace()
issues += createAndLogIssue(
source = managerName,
message = "Could not resolve VCS information for project '$name': ${e.collectMessages()}"
)
VcsInfo.EMPTY
}
val pkg = Package(
id = Identifier("Go", "", name, normalizeModuleVersion(version)),
authors = emptySet(),
declaredLicenses = emptySet(),
description = "",
homepageUrl = "",
binaryArtifact = RemoteArtifact.EMPTY,
sourceArtifact = RemoteArtifact.EMPTY,
vcs = VcsInfo.EMPTY,
vcsProcessed = vcsProcessed
)
packages += pkg
packageRefs += pkg.toReference(linkage = PackageLinkage.STATIC, issues = issues)
}
val scope = Scope("default", packageRefs)
val projectName = runCatching {
val uri = URI(projectVcs.url)
val vcsPath = VersionControlSystem.getPathInfo(definitionFile.parentFile).path
listOf(uri.host, uri.path.removePrefix("/").removeSuffix(".git"), vcsPath)
.filterNot { it.isEmpty() }
.joinToString(separator = "/")
.lowercase()
}.getOrDefault(getFallbackProjectName(analysisRoot, definitionFile))
// TODO Keeping this between scans would speed things up considerably.
gopath.safeDeleteRecursively(force = true)
return listOf(
ProjectAnalyzerResult(
project = Project(
id = Identifier(
type = managerName,
namespace = "",
name = projectName,
version = projectVcs.revision
),
definitionFilePath = VersionControlSystem.getPathInfo(definitionFile).path,
authors = emptySet(),
declaredLicenses = emptySet(),
vcs = VcsInfo.EMPTY,
vcsProcessed = projectVcs,
homepageUrl = "",
scopeDependencies = setOf(scope)
),
packages = packages
)
)
}
private fun importLegacyManifest(lockfileName: String, workingDir: File, gopath: File) {
requireLockfile(workingDir) { lockfileName.isEmpty() || workingDir.resolve(lockfileName).isFile }
run("init", workingDir = workingDir, environment = mapOf("GOPATH" to gopath.realFile().path))
}
private fun setUpWorkspace(projectDir: File, vcs: VcsInfo, gopath: File): File {
val destination = deduceImportPath(projectDir, vcs, gopath)
logger.debug { "Copying $projectDir to temporary directory $destination" }
projectDir.toPath().copyToRecursively(
destination.toPath().apply { parent?.createDirectories() },
followLinks = false
)
val dotGit = File(destination, ".git")
if (dotGit.isFile) {
// HACK "dep" seems to be confused by git submodules. We detect this by checking whether ".git" exists
// and is a regular file instead of a directory.
dotGit.delete()
}
return destination
}
private fun parseProjects(workingDir: File, gopath: File): List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy