diff --git a/lib/bucket_archive_direct_read.go b/lib/bucket_archive_direct_read.go
new file mode 100644
index 00000000..ace355f3
--- /dev/null
+++ b/lib/bucket_archive_direct_read.go
@@ -0,0 +1,267 @@
+package lib
+
+import (
+ "fmt"
+ "github.com/aliyun/aliyun-oss-go-sdk/oss"
+ "io/ioutil"
+ "os"
+ "strings"
+)
+
+var specChineseBucketArchiveDirectRead = SpecText{
+ synopsisText: "设置、查询bucket的archive direct read配置",
+ paramText: "bucket_url local_xml_file [options]",
+
+ syntaxText: `
+ ossutil archive-direct-read --method put oss://bucket local_xml_file [options]
+ ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options]
+`,
+ detailHelpText: `
+ archive-direct-read命令通过设置method选项值为put、get,可以设置、查询bucket的archive direct read配置
+
+用法:
+ 该命令有二种用法:
+
+ 1) ossutil archive-direct-read --method put oss://bucket local_xml_file [options]
+ 这个命令从配置文件local_xml_file中读取archive direct read配置,然后设置bucket的archive direct read规则
+ 配置文件是一个xml格式的文件,下面是一个所有规则的例子
+
+
+
+ true
+
+
+ 2) ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options]
+ 这个命令查询bucket的archive direct read配置
+ 如果输入参数local_xml_file,archive direct read配置将输出到该文件,否则输出到屏幕上
+
+`,
+ sampleText: `
+ 1) 设置bucket的archive direct read配置
+ ossutil archive-direct-read --method put oss://bucket local_xml_file
+
+ 2) 查询bucket的archive direct read配置,结果输出到标准输出
+ ossutil archive-direct-read --method get oss://bucket
+
+ 3) 查询bucket的archive direct read配置,结果输出到本地文件
+ ossutil archive-direct-read --method get oss://bucket local_xml_file
+`,
+}
+
+var specEnglishBucketArchiveDirectRead = SpecText{
+ synopsisText: "Set, get bucket archive direct read configuration",
+ paramText: "bucket_url local_xml_file [options]",
+
+ syntaxText: `
+ ossutil archive-direct-read --method put oss://bucket local_xml_file [options]
+ ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options]
+`,
+
+ detailHelpText: `
+ archive-direct-read command can set, get the archive direct read configuration of the oss bucket by
+ set method option value to put, get
+
+Usage:
+ 1) ossutil archive-direct-read --method put oss://bucket local_xml_file [options]
+ The command sets the lifecycle configuration of bucket from local file local_xml_file
+ the local_xml_file is xml format, you can choose to configure only some rules
+ The following is an example of all rules:
+
+
+
+ true
+
+
+ 2) ossutil archive-direct-read --method get oss://bucket [local_xml_file] [options]
+ The command gets the archive direct read configuration of bucket
+ If you input parameter local_xml_file,the configuration will be output to local_xml_file
+ If you don't input parameter local_xml_file,the configuration will be output to stdout
+`,
+
+ sampleText: `
+ 1) put bucket archive direct read
+ ossutil archive-direct-read --method put oss://bucket local_xml_file
+
+ 2) get bucket archive direct read configuration to stdout
+ ossutil archive-direct-read --method get oss://bucket
+
+ 3) get bucket archive direct read configuration to local file
+ ossutil archive-direct-read --method get oss://bucket local_xml_file
+`,
+}
+
+type bucketArchiveDirectReadOptionType struct {
+ bucketName string
+}
+
+type BucketArchiveDirectReadCommand struct {
+ command Command
+ blOption bucketArchiveDirectReadOptionType
+}
+
+var bucketArchiveDirectReadCommand = BucketArchiveDirectReadCommand{
+ command: Command{
+ name: "archive-direct-read",
+ nameAlias: []string{"archive-direct-read"},
+ minArgc: 1,
+ maxArgc: 2,
+ specChinese: specChineseBucketArchiveDirectRead,
+ specEnglish: specEnglishBucketArchiveDirectRead,
+ group: GroupTypeNormalCommand,
+ validOptionNames: []string{
+ OptionConfigFile,
+ OptionEndpoint,
+ OptionAccessKeyID,
+ OptionAccessKeySecret,
+ OptionSTSToken,
+ OptionProxyHost,
+ OptionProxyUser,
+ OptionProxyPwd,
+ OptionLogLevel,
+ OptionMethod,
+ OptionPassword,
+ OptionMode,
+ OptionECSRoleName,
+ OptionTokenTimeout,
+ OptionRamRoleArn,
+ OptionRoleSessionName,
+ OptionReadTimeout,
+ OptionConnectTimeout,
+ OptionSTSRegion,
+ OptionSkipVerifyCert,
+ OptionUserAgent,
+ OptionSignVersion,
+ OptionRegion,
+ OptionCloudBoxID,
+ },
+ },
+}
+
+// function for FormatHelper interface
+func (badr *BucketArchiveDirectReadCommand) formatHelpForWhole() string {
+ return badr.command.formatHelpForWhole()
+}
+
+func (badr *BucketArchiveDirectReadCommand) formatIndependHelp() string {
+ return badr.command.formatIndependHelp()
+}
+
+// Init simulate inheritance, and polymorphism
+func (badr *BucketArchiveDirectReadCommand) Init(args []string, options OptionMapType) error {
+ return badr.command.Init(args, options, badr)
+}
+
+// RunCommand simulate inheritance, and polymorphism
+func (badr *BucketArchiveDirectReadCommand) RunCommand() error {
+ strMethod, _ := GetString(OptionMethod, badr.command.options)
+ if strMethod == "" {
+ return fmt.Errorf("--method value is empty")
+ }
+
+ strMethod = strings.ToLower(strMethod)
+ if strMethod != "put" && strMethod != "get" && strMethod != "delete" {
+ return fmt.Errorf("--method value is not in the optional value:put|get|delete")
+ }
+
+ srcBucketUrL, err := GetCloudUrl(badr.command.args[0], "")
+ if err != nil {
+ return err
+ }
+
+ badr.blOption.bucketName = srcBucketUrL.bucket
+
+ switch strMethod {
+ case "put":
+ err = badr.PutBucketArchiveDirectRead()
+ case "get":
+ err = badr.GetBucketArchiveDirectRead()
+ }
+ return err
+}
+
+func (badr *BucketArchiveDirectReadCommand) PutBucketArchiveDirectRead() error {
+ if len(badr.command.args) < 2 {
+ return fmt.Errorf("put bucket archive direct read need at least 2 parameters,the local xml file is empty")
+ }
+
+ xmlFile := badr.command.args[1]
+ fileInfo, err := os.Stat(xmlFile)
+ if err != nil {
+ return err
+ }
+
+ if fileInfo.IsDir() {
+ return fmt.Errorf("%s is dir,not the expected file", xmlFile)
+ }
+
+ if fileInfo.Size() == 0 {
+ return fmt.Errorf("%s is empty file", xmlFile)
+ }
+
+ // parsing the xml file
+ file, err := os.Open(xmlFile)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ xmlBody, err := ioutil.ReadAll(file)
+ if err != nil {
+ return err
+ }
+
+ // put bucket lifecycle
+ client, err := badr.command.ossClient(badr.blOption.bucketName)
+ if err != nil {
+ return err
+ }
+
+ options := []oss.Option{oss.AllowSameActionOverLap(true)}
+ return client.PutBucketArchiveDirectReadXml(badr.blOption.bucketName, string(xmlBody), options...)
+}
+
+func (badr *BucketArchiveDirectReadCommand) confirm(str string) bool {
+ var val string
+ fmt.Printf(getClearStr(fmt.Sprintf("bucket archive direct read: overwrite \"%s\"(y or N)? ", str)))
+ if _, err := fmt.Scanln(&val); err != nil || (strings.ToLower(val) != "yes" && strings.ToLower(val) != "y") {
+ return false
+ }
+ return true
+}
+
+func (badr *BucketArchiveDirectReadCommand) GetBucketArchiveDirectRead() error {
+ client, err := badr.command.ossClient(badr.blOption.bucketName)
+ if err != nil {
+ return err
+ }
+
+ output, err := client.GetBucketArchiveDirectReadXml(badr.blOption.bucketName)
+ if err != nil {
+ return err
+ }
+
+ var outFile *os.File
+ if len(badr.command.args) >= 2 {
+ fileName := badr.command.args[1]
+ _, err = os.Stat(fileName)
+ if err == nil {
+ bConitnue := badr.confirm(fileName)
+ if !bConitnue {
+ return nil
+ }
+ }
+
+ outFile, err = os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0660)
+ if err != nil {
+ return err
+ }
+ defer outFile.Close()
+ } else {
+ outFile = os.Stdout
+ }
+
+ outFile.Write([]byte(output))
+
+ fmt.Printf("\n\n")
+
+ return nil
+}
diff --git a/lib/bucket_archive_direct_read_test.go b/lib/bucket_archive_direct_read_test.go
new file mode 100644
index 00000000..b8348660
--- /dev/null
+++ b/lib/bucket_archive_direct_read_test.go
@@ -0,0 +1,207 @@
+package lib
+
+import (
+ "encoding/xml"
+ "github.com/aliyun/aliyun-oss-go-sdk/oss"
+ . "gopkg.in/check.v1"
+ "os"
+)
+
+func (s *OssutilCommandSuite) TestArchiveDirectReadHelpInfo(c *C) {
+ // mkdir command test
+ options := OptionMapType{}
+
+ mkArgs := []string{"archive-direct-read"}
+ _, err := cm.RunCommand("help", mkArgs, options)
+ c.Assert(err, IsNil)
+
+ mkArgs = []string{}
+ _, err = cm.RunCommand("help", mkArgs, options)
+ c.Assert(err, IsNil)
+}
+
+func (s *OssutilCommandSuite) TestPutBucketArchiveDirectReadError(c *C) {
+ bucketName := bucketNamePrefix + randLowStr(12)
+ s.putBucket(bucketName, c)
+
+ archiveFileName := "archive-direct-read" + randLowStr(12)
+
+ strMethod := ""
+ options := OptionMapType{
+ "endpoint": &endpoint,
+ "accessKeyID": &accessKeyID,
+ "accessKeySecret": &accessKeySecret,
+ "method": &strMethod,
+ }
+
+ // method is empty
+ archiveArgs := []string{CloudURLToString(bucketName, ""), archiveFileName}
+ _, err := cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ //method is error
+ strMethod = "puttt"
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ // cloudurl is error
+ strMethod = "put"
+ archiveArgs = []string{"http://mybucket", archiveFileName}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ // local file is emtpy
+ archiveArgs = []string{CloudURLToString(bucketName, ""), archiveFileName}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ //local file is not exist
+ os.Remove(archiveFileName)
+ archiveArgs = []string{CloudURLToString(bucketName, ""), archiveFileName}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ // local file is dir
+ err = os.MkdirAll(archiveFileName, 0755)
+ c.Assert(err, IsNil)
+ archiveArgs = []string{CloudURLToString(bucketName, ""), archiveFileName}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+ os.Remove(archiveFileName)
+
+ //local file is empty
+ s.createFile(archiveFileName, "", c)
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+ os.Remove(archiveFileName)
+
+ //local file is not xml file
+ s.createFile(archiveFileName, "aaa", c)
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+ os.Remove(archiveFileName)
+
+ // StorageURLFromString error
+ archiveArgs = []string{"oss:///1.jpg"}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ // bucketname is error
+ archiveArgs = []string{"oss:///"}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ //missing parameter
+ archiveArgs = []string{CloudURLToString(bucketName, "")}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ // bucketname not exist
+ archiveArgs = []string{CloudURLToString("my-bucket", "")}
+ _, err = cm.RunCommand("archive-direct-read", archiveArgs, options)
+ c.Assert(err, NotNil)
+
+ os.Remove(archiveFileName)
+ s.removeBucket(bucketName, true, c)
+}
+
+func (s *OssutilCommandSuite) TestPutBucketArchiveDirectRead(c *C) {
+ archiveXml := `
+
+ true
+`
+
+ archiveConfigSrc := oss.PutBucketArchiveDirectRead{}
+ err := xml.Unmarshal([]byte(archiveXml), &archiveConfigSrc)
+ c.Assert(err, IsNil)
+
+ archiveFileName := randLowStr(12)
+ s.createFile(archiveFileName, archiveXml, c)
+
+ bucketName := bucketNamePrefix + randLowStr(12)
+ s.putBucket(bucketName, c)
+
+ strMethod := "put"
+ options := OptionMapType{
+ "endpoint": &endpoint,
+ "accessKeyID": &accessKeyID,
+ "accessKeySecret": &accessKeySecret,
+ "method": &strMethod,
+ }
+
+ testLogger.Println(endpoint)
+
+ command := "archive-direct-read"
+ archiveArgs := []string{CloudURLToString(bucketName, ""), archiveFileName}
+ _, err = cm.RunCommand(command, archiveArgs, options)
+ c.Assert(err, IsNil)
+
+ archiveDownName := archiveFileName + "-down"
+ strMethod = "get"
+ options[OptionMethod] = &strMethod
+
+ archiveArgs = []string{CloudURLToString(bucketName, ""), archiveDownName}
+ _, err = cm.RunCommand(command, archiveArgs, options)
+ c.Assert(err, IsNil)
+
+ _, err = os.Stat(archiveDownName)
+ c.Assert(err, IsNil)
+
+ accessBody := s.readFile(archiveDownName, c)
+
+ var out oss.GetBucketArchiveDirectReadResult
+ err = xml.Unmarshal([]byte(accessBody), &out)
+ c.Assert(err, IsNil)
+
+ c.Assert(archiveConfigSrc.Enabled, Equals, out.Enabled)
+
+ os.Remove(archiveFileName)
+ os.Remove(archiveDownName)
+ s.removeBucket(bucketName, true, c)
+}
+
+func (s *OssutilCommandSuite) TestGetBucketArchiveDirectReadConfirm(c *C) {
+ bucketName := bucketNamePrefix + randLowStr(12)
+ s.putBucket(bucketName, c)
+
+ archiveXml := `
+
+ true
+`
+
+ archiveFileName := inputFileName + randLowStr(5)
+ s.createFile(archiveFileName, archiveXml, c)
+
+ strMethod := "put"
+ options := OptionMapType{
+ "endpoint": &endpoint,
+ "accessKeyID": &accessKeyID,
+ "accessKeySecret": &accessKeySecret,
+ "method": &strMethod,
+ }
+
+ command := "archive-direct-read"
+ archiveArgs := []string{CloudURLToString(bucketName, ""), archiveFileName}
+ _, err := cm.RunCommand(command, archiveArgs, options)
+ c.Assert(err, IsNil)
+
+ archiveDownName := archiveFileName + "-down"
+ strMethod = "get"
+ options[OptionMethod] = &strMethod
+
+ archiveArgs = []string{CloudURLToString(bucketName, ""), archiveDownName}
+ _, err = cm.RunCommand(command, archiveArgs, options)
+ c.Assert(err, IsNil)
+
+ archiveArgs = []string{CloudURLToString(bucketName, ""), archiveDownName}
+ _, err = cm.RunCommand(command, archiveArgs, options)
+ c.Assert(err, IsNil)
+
+ archiveArgs = []string{CloudURLToString(bucketName, "")}
+ _, err = cm.RunCommand(command, archiveArgs, options)
+ c.Assert(err, IsNil)
+
+ os.Remove(archiveFileName)
+ os.Remove(archiveDownName)
+ s.removeBucket(bucketName, true, c)
+}
diff --git a/lib/command.go b/lib/command.go
index 7777bb73..ae3a78cb 100644
--- a/lib/command.go
+++ b/lib/command.go
@@ -896,5 +896,6 @@ func GetAllCommands() []interface{} {
&lcbCommand,
&bucketAccessMonitorCommand,
&bucketResourceGroupCommand,
+ &bucketArchiveDirectReadCommand,
}
}