Skip to content

Commit

Permalink
feat: add appimage convert feature
Browse files Browse the repository at this point in the history
implement appimage convert feature, this feature was moved from linglong builder

Log:
  • Loading branch information
dengbo11 committed Sep 3, 2024
1 parent 560a151 commit 4d953e9
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ PBUILDER_PKG = pbuilder-satisfydepends-dummy
PREFIX = usr
BINARY_DIR = bin
BINARY_NAME = ll-pica
APPIMAGE_CONVERT_BINARY_NAME = ll-appimage-convert
GO_PATH = /tmp/go
GO_CACHE = /tmp/go-cache
GoPath := GOPATH=${GO_PATH}
Expand All @@ -18,21 +19,26 @@ all: build
build:
install -d ${GO_PATH} ${GO_CACHE}
CGO_ENABLED=0 ${GoPath} ${GOBUILD} -o ${BINARY_DIR}/${BINARY_NAME} ./cmd/${BINARY_NAME}
CGO_ENABLED=0 ${GoPath} ${GOBUILD} -o ${BINARY_DIR}/${APPIMAGE_CONVERT_BINARY_NAME} ./cmd/${APPIMAGE_CONVERT_BINARY_NAME}

debug:
${GoPath} ${GOBUILDDEBUG} -o ${BINARY_DIR}/${BINARY_NAME} ./cmd/${BINARY_NAME}
${GoPath} ${GOBUILDDEBUG} -o ${BINARY_DIR}/${APPIMAGE_CONVERT_BINARY_NAME} ./cmd/${APPIMAGE_CONVERT_BINARY_NAME}

test:
${GoPath} ${GOTEST} ./tools/...

install:
install -Dm0755 ${BINARY_DIR}/${BINARY_NAME} ${DESTDIR}/${PREFIX}/${BINARY_DIR}/${BINARY_NAME}
install -Dm0755 ${BINARY_DIR}/${APPIMAGE_CONVERT_BINARY_NAME} ${DESTDIR}/${PREFIX}/${BINARY_DIR}/${APPIMAGE_CONVERT_BINARY_NAME}

install -d ${DESTDIR}/${PREFIX}/share/linglong/builder/helper/
install -Dm0755 misc/libexec/linglong/builder/helper/install_dep ${DESTDIR}/${PREFIX}/libexec/linglong/builder/helper/install_dep
clean:
rm -rf ${BINARY_DIR}
rm -rf ${APPIMAGE_CONVERT_BINARY_NAME}
rm -rf ${GO_PATH}
rm -rf ${GO_CACHE}

.PHONY: ${BINARY_NAME}
.PHONY: ${APPIMAGE_CONVERT_BINARY_NAME}
197 changes: 197 additions & 0 deletions cli/appimage/convert/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
* SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

package convert

import (
"fmt"
"os"
"path"
"path/filepath"

"github.com/spf13/cobra"
"pkg.deepin.com/linglong/pica/cli/comm"
"pkg.deepin.com/linglong/pica/cli/linglong"
"pkg.deepin.com/linglong/pica/tools/fs"
"pkg.deepin.com/linglong/pica/tools/log"
)

type convertOptions struct {
packageId string
packageName string
packageVersion string
packageDescription string
appimageFile string
appimageFileUrl string
appimageFileHash string
buildFlag bool
exportLayerFlag bool
}

func NewConvertCommand() *cobra.Command {
var options convertOptions

cmd := &cobra.Command{
Use: "convert",
Short: "Convert appimage to uab",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
return runConvert(&options)
},
}

flags := cmd.Flags()
flags.StringVarP(&options.packageId, "id", "i", "", "the unique name of the package")
flags.StringVarP(&options.packageName, "name", "n", "", "the description the package")
flags.StringVarP(&options.packageVersion, "version", "v", "", "the version of the package")
flags.StringVarP(&options.packageDescription, "description", "d", "", "detailed description of the package")
flags.StringVarP(&options.appimageFile, "file", "f", "", `app package file, it not required option,
you can ignore this option
when you set --url option and --hash option`)
flags.StringVarP(&options.appimageFileUrl, "url", "u", "", "pkg url, it not required option,you can ignore this option when you set -f option")
flags.StringVarP(&options.appimageFileHash, "hash", "", "", "pkg hash value, it must be used with --url option")
flags.BoolVarP(&options.buildFlag, "build", "b", false, "build linglong")
flags.BoolVarP(&options.exportLayerFlag, "layer", "l", false, "export layer file")
return cmd
}

func runConvert(options *convertOptions) error {
if options.packageId == "" {
return fmt.Errorf("package id is required")
}

if options.packageVersion == "" {
return fmt.Errorf("package version is required")
}

if options.appimageFile == "" && options.appimageFileUrl == "" {
return fmt.Errorf("file option or url option is required")
}

if options.appimageFileUrl != "" && options.appimageFileHash == "" {
return fmt.Errorf("hash option is required when use url option")
}

var suffix string
if options.appimageFile != "" {
suffix = path.Ext(options.appimageFile)
} else {
suffix = path.Ext(options.appimageFileUrl)
}

appImageFileType := suffix == ".AppImage" || suffix == ".appimage"

if !appImageFileType {
return fmt.Errorf("appimage file must be .AppImage or .appimage")
}

var build []string

build = append(build, []string{
"cd linglong/sources",
"APPIMAGE=$(find . -regex '.*\\.AppImage\\|.*appimage' -exec basename {} \\;)",
"chmod +x ${APPIMAGE}",
"./${APPIMAGE} --appimage-extract",
"BINNAME=${LINGLONG_APPID}",
"APP_PREFIX=${BINNAME}",
"echo \"#!/usr/bin/env bash\" > ${BINNAME}",
"echo \"unset LD_LIBRARY_PATH\" >> ${BINNAME}",
"echo \"cd ${PREFIX}/lib/${APP_PREFIX} && ./AppRun $@\" >> ${BINNAME}",
"# only search for .desktop file in the squashfs-root directory",
"DESKTOP_FILE=$(find squashfs-root -maxdepth 1 -regex '.*\\.desktop' -exec basename {} \\;)",
"cp squashfs-root/${DESKTOP_FILE} .",
"sed -i \"s@Exec=.*@Exec=${PREFIX}/bin/${BINNAME}@\" ${DESKTOP_FILE}",

"cd squashfs-root",
"if [ ! $PREFIX ]; then",
" PREFIX=opt/${APP_PREFIX}",
"fi",
"DESTDIR=${dest_dir}",
"# install icons to linglong package",
"if [ -d usr/share/icons ]; then",
" cd usr",
" find share/icons -type f -exec install -D \"{}\" \"${DESTDIR}/${PREFIX}/{}\" \\;",
" cd ..",
"fi",
"find -type d -exec install -d \"${DESTDIR}/${PREFIX}/lib/${APP_PREFIX}/{}\" \\;",
"find -type f -exec install -D \"{}\" \"${DESTDIR}/${PREFIX}/lib/${APP_PREFIX}/{}\" \\;",
"find -type l -exec bash -c \"ln -s \\$(readlink {}) \"${DESTDIR}/${PREFIX}/lib/${APP_PREFIX}/{}\" \" -exec install -D \"{}\" \"${DESTDIR}/${PREFIX}/lib/${APP_PREFIX}/{}\" \\;",
"cd ..",
"install -D ${BINNAME} ${DESTDIR}/${PREFIX}/bin/${BINNAME}",
"install -D ${DESKTOP_FILE} ${DESTDIR}/${PREFIX}/share/applications/${DESKTOP_FILE}",
}...)

builder := linglong.LinglongBuilder{
Package: linglong.Package{
Appid: options.packageId,
Name: options.packageName,
Version: options.packageVersion,
Kind: "app",
Description: options.packageDescription,
},
Base: fmt.Sprintf("%s/%s", "org.deepin.foundation", "20.0.0"),
Command: []string{
fmt.Sprintf("/opt/apps/%s/files/bin/%s", options.packageId, options.packageId),
},
Build: build,
}

if options.appimageFileUrl != "" && options.appimageFileHash != "" {
var sources []comm.Source
sources = append(sources, comm.Source{Kind: "file", Digest: options.appimageFileHash, Url: options.appimageFileUrl})
builder.Sources = sources
}

workDir := options.packageId

if exited, err := fs.CreateDir(workDir); !exited {
log.Logger.Errorf("create workdir %s: failed: %s", workDir, err)
}

// 复制appimage文件到linglong/sources目录
if options.appimageFile != "" {
data, err := os.ReadFile(options.appimageFile)
if err != nil {
return err
}

err = os.MkdirAll(comm.LLSourcePath(workDir), 0755)
if err != nil {
return err
}

destinationFilePath := filepath.Join(comm.LLSourcePath(workDir), filepath.Base(options.appimageFile))
err = os.WriteFile(destinationFilePath, data, 0644)
if err != nil {
return err
}
}

linglongYamlPath := filepath.Join(workDir, comm.LinglongYaml)

// 生成 linglong.yaml 文件
if builder.CreateLinglongYaml(linglongYamlPath) {
log.Logger.Infof("generate %s success.", comm.LinglongYaml)
} else {
log.Logger.Errorf("generate %s failed", comm.LinglongYaml)
}

log.Logger.Info("building linglong package")

// 构建玲珑包
if options.buildFlag {
buildLinglongPath := filepath.Dir(linglongYamlPath)
builder.LinglongBuild(buildLinglongPath)

layerOpt := "uab"
if options.exportLayerFlag {
layerOpt = "layer"
}
builder.LinglongExport(buildLinglongPath, layerOpt)
}

return nil
}
5 changes: 5 additions & 0 deletions cli/cobra.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ func setupCommonRootCommand(rootCmd *cobra.Command) (*cliflags.CliOptions, *cobr
return opts, nil
}

func AppimageConvertSetupRootCommand(rootCmd *cobra.Command) (opts *cliflags.CliOptions, helpCmd *cobra.Command) {
rootCmd.SetVersionTemplate("ll-appimage-convert version {{.Version}}\n")
return setupCommonRootCommand(rootCmd)
}

func SetupRootCommand(rootCmd *cobra.Command) (opts *cliflags.CliOptions, helpCmd *cobra.Command) {
rootCmd.SetVersionTemplate("pica version {{.Version}}\n")
return setupCommonRootCommand(rootCmd)
Expand Down
50 changes: 50 additions & 0 deletions cmd/ll-appimage-convert/ll-appimage-convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

package main

import (
"os"

"github.com/spf13/cobra"

"pkg.deepin.com/linglong/pica/cli"
"pkg.deepin.com/linglong/pica/cli/appimage/convert"
"pkg.deepin.com/linglong/pica/tools/log"
)

func main() {
log.Logger = log.InitLog()
defer log.Logger.Sync()

if err := run(); err != nil {
log.Logger.Errorf("run pica failed: %v", err)
os.Exit(1)
}
}

func newAppimageConvertCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "ll-appimage-convert",
Short: "appimage package convert linglong package",
Long: `Convert the appimage to uab. For example:
Simple:
ll-appimage-convert convert -f xxx.appimage -i "io.github.demo" -n "io.github.demo" -v "1.0.0.0" -d "this is a appimage convert demo" -b
ll-appimage-convert help
`,
Version: "1.0.0",
}

cmd.CompletionOptions.DisableDefaultCmd = true
cli.AppimageConvertSetupRootCommand(cmd)
cmd.AddCommand(convert.NewConvertCommand())
return cmd
}

func run() error {
cmd := newAppimageConvertCommand()
return cmd.Execute()
}

0 comments on commit 4d953e9

Please sign in to comment.